unique-search-proxy 0.2.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.
- unique_search_proxy-0.2.0/PKG-INFO +315 -0
- unique_search_proxy-0.2.0/README.md +297 -0
- unique_search_proxy-0.2.0/pyproject.toml +60 -0
- unique_search_proxy-0.2.0/unique_search_proxy/__init__.py +0 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/__init__.py +0 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/app.py +116 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/__init__.py +30 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/google_search/__init__.py +6 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/google_search/exceptions.py +26 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/google_search/schema.py +21 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/google_search/search.py +110 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/google_search/settings.py +15 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/schema.py +59 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/__init__.py +6 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/client.py +34 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/config.py +39 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/exceptions.py +25 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/gemini.py +24 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/helpers.py +25 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/prompts.py +28 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/response_handler.py +87 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/search.py +96 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/core/vertexai/settings.py +13 -0
- unique_search_proxy-0.2.0/unique_search_proxy/web/settings.py +6 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: unique-search-proxy
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Web Search Proxy implementation
|
|
5
|
+
Author: ThePhilAz
|
|
6
|
+
Author-email: ThePhilAz <rami.azouz@philico.com>
|
|
7
|
+
Requires-Dist: fastapi>=0.115.0,<1.0.0
|
|
8
|
+
Requires-Dist: uvicorn[standard]>=0.32.0,<1.0.0
|
|
9
|
+
Requires-Dist: google-cloud-aiplatform>=1.128.0,<2.0.0
|
|
10
|
+
Requires-Dist: google-auth>=2.43.0,<3.0.0
|
|
11
|
+
Requires-Dist: google-generativeai>=0.8.5,<0.9.0
|
|
12
|
+
Requires-Dist: pydantic>=2.12.5,<3.0.0
|
|
13
|
+
Requires-Dist: httpx>=0.28.0,<0.29.0
|
|
14
|
+
Requires-Dist: python-dotenv>=1.2.1,<2.0.0
|
|
15
|
+
Requires-Dist: pydantic-settings>=2.12.0,<3.0.0
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# Unique Search Proxy
|
|
20
|
+
|
|
21
|
+
A unified web search proxy API that provides a consistent interface for multiple search backends. Built with FastAPI and designed for seamless integration with AI applications.
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
This service acts as an abstraction layer over different search providers, allowing clients to switch between search engines without changing their integration code. Currently supports:
|
|
26
|
+
|
|
27
|
+
| Engine | Description |
|
|
28
|
+
|--------|-------------|
|
|
29
|
+
| **Google Custom Search** | Direct integration with Google's Custom Search JSON API |
|
|
30
|
+
| **Vertex AI (Gemini)** | AI-powered search using Google's Gemini models with grounding capabilities |
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Prerequisites
|
|
35
|
+
|
|
36
|
+
- Python 3.12+
|
|
37
|
+
- uv for dependency management
|
|
38
|
+
- Google Cloud credentials (for Vertex AI)
|
|
39
|
+
- Google Custom Search API key and Engine ID (for Google Search)
|
|
40
|
+
|
|
41
|
+
### Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Install dependencies
|
|
45
|
+
uv sync
|
|
46
|
+
|
|
47
|
+
# Copy and configure environment variables
|
|
48
|
+
cp .env.example .env
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Environment Variables
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Google Custom Search
|
|
55
|
+
GOOGLE_SEARCH_API_KEY=your-api-key
|
|
56
|
+
GOOGLE_SEARCH_API_ENDPOINT=https://www.googleapis.com/customsearch/v1
|
|
57
|
+
GOOGLE_SEARCH_ENGINE_ID=your-engine-id
|
|
58
|
+
|
|
59
|
+
# Vertex AI
|
|
60
|
+
VERTEXAI_SERVICE_ACCOUNT_CREDENTIALS=path/to/credentials.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Running the Service
|
|
64
|
+
|
|
65
|
+
**Development:**
|
|
66
|
+
```bash
|
|
67
|
+
uv run python -m unique_search_proxy.web.app
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Docker (from published package — hash-verified):**
|
|
71
|
+
|
|
72
|
+
CI generates a hash-pinned `requirements.txt` from `uv.lock` and passes it into the
|
|
73
|
+
Docker build. Dependencies are installed with `--require-hashes`, then the package
|
|
74
|
+
itself is installed with `--no-deps`. To reproduce locally:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv export --locked --package unique-search-proxy --no-dev --no-emit-project \
|
|
78
|
+
-o deploy/requirements.txt
|
|
79
|
+
docker build --build-arg PACKAGE_VERSION=0.2.0 -t search-proxy deploy/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Every transitive dependency is verified against its sha256 hash from the lockfile.
|
|
83
|
+
|
|
84
|
+
**Docker (from local source — no registry required):**
|
|
85
|
+
|
|
86
|
+
Build a wheel first, copy it into `deploy/`, then reference it:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv build --wheel --out-dir deploy/
|
|
90
|
+
docker build \
|
|
91
|
+
--build-arg LOCAL_WHEEL=unique_search_proxy-0.2.0-py3-none-any.whl \
|
|
92
|
+
-t search-proxy deploy/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Running the container:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker run --rm -p 8080:8080 search-proxy
|
|
99
|
+
|
|
100
|
+
# With custom environment variables
|
|
101
|
+
docker run --rm -p 8080:8080 -e WORKERS=8 -e LOG_LEVEL=debug search-proxy
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API Documentation
|
|
105
|
+
|
|
106
|
+
FastAPI provides automatic interactive API documentation:
|
|
107
|
+
|
|
108
|
+
| URL | Description |
|
|
109
|
+
|-----|-------------|
|
|
110
|
+
| `/docs` | Swagger UI - interactive API explorer |
|
|
111
|
+
| `/redoc` | ReDoc - alternative documentation |
|
|
112
|
+
| `/openapi.json` | OpenAPI schema |
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### Health Check
|
|
117
|
+
|
|
118
|
+
```http
|
|
119
|
+
GET /health
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Response:**
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"status": "healthy"
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### Search
|
|
132
|
+
|
|
133
|
+
```http
|
|
134
|
+
POST /search
|
|
135
|
+
Content-Type: application/json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Request Body:**
|
|
139
|
+
|
|
140
|
+
| Field | Type | Required | Description |
|
|
141
|
+
|-------|------|----------|-------------|
|
|
142
|
+
| `search_engine` | string | No | `"google"` or `"vertexai"` (default: `"google"`) |
|
|
143
|
+
| `query` | string | Yes | The search query |
|
|
144
|
+
| `kwargs` | object | No | Engine-specific parameters |
|
|
145
|
+
|
|
146
|
+
**Response:**
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"results": [
|
|
150
|
+
{
|
|
151
|
+
"url": "https://example.com/article",
|
|
152
|
+
"title": "Article Title",
|
|
153
|
+
"snippet": "A brief description of the content...",
|
|
154
|
+
"content": ""
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Search Engine Configuration
|
|
163
|
+
|
|
164
|
+
### Google Custom Search
|
|
165
|
+
|
|
166
|
+
Uses Google's Custom Search JSON API for traditional web search results.
|
|
167
|
+
|
|
168
|
+
**Parameters (`kwargs`):**
|
|
169
|
+
|
|
170
|
+
| Parameter | Type | Default | Description |
|
|
171
|
+
|-----------|------|---------|-------------|
|
|
172
|
+
| `cx` | string | env default | Custom Search Engine ID (overrides env) |
|
|
173
|
+
| `fetchSize` | int | 10 | Number of results to fetch |
|
|
174
|
+
| `timeout` | int | 10 | Request timeout in seconds |
|
|
175
|
+
|
|
176
|
+
**Example:**
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"search_engine": "google",
|
|
180
|
+
"query": "latest AI developments",
|
|
181
|
+
"kwargs": {
|
|
182
|
+
"fetchSize": 20,
|
|
183
|
+
"timeout": 15
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### Vertex AI (Gemini)
|
|
191
|
+
|
|
192
|
+
Leverages Google's Gemini models with web grounding for AI-enhanced search results. This engine:
|
|
193
|
+
|
|
194
|
+
1. Uses Gemini to search and synthesize information from the web
|
|
195
|
+
2. Generates structured results with citations
|
|
196
|
+
3. Optionally resolves shortened/redirect URLs to final destinations
|
|
197
|
+
|
|
198
|
+
**Parameters (`kwargs`):**
|
|
199
|
+
|
|
200
|
+
| Parameter | Type | Default | Description |
|
|
201
|
+
|-----------|------|---------|-------------|
|
|
202
|
+
| `modelName` | string | `"gemini-2.5-flash"` | Gemini model to use |
|
|
203
|
+
| `entrepriseSearch` | bool | `false` | Use Enterprise Web Search |
|
|
204
|
+
| `systemInstruction` | string | (built-in) | Custom system prompt |
|
|
205
|
+
| `resolveUrls` | bool | `true` | Resolve redirect URLs |
|
|
206
|
+
|
|
207
|
+
**Example:**
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"search_engine": "vertexai",
|
|
211
|
+
"query": "Compare the top 3 cloud providers for ML workloads",
|
|
212
|
+
"kwargs": {
|
|
213
|
+
"modelName": "gemini-2.5-flash",
|
|
214
|
+
"resolveUrls": true
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Project Structure
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
connectors/unique_search_proxy/
|
|
225
|
+
├── unique_search_proxy/ # Python package (published to PyPI)
|
|
226
|
+
│ ├── __init__.py
|
|
227
|
+
│ └── web/ # Web search API sub-module
|
|
228
|
+
│ ├── __init__.py
|
|
229
|
+
│ ├── app.py # FastAPI application
|
|
230
|
+
│ ├── settings.py # Global settings
|
|
231
|
+
│ └── core/ # Search engine implementations
|
|
232
|
+
│ ├── schema.py # Shared schemas
|
|
233
|
+
│ ├── google_search/ # Google Custom Search backend
|
|
234
|
+
│ └── vertexai/ # Vertex AI (Gemini) backend
|
|
235
|
+
├── tests/ # Test suite
|
|
236
|
+
├── deploy/ # Container build artifacts
|
|
237
|
+
│ ├── Dockerfile # Hash-verified install or local wheel
|
|
238
|
+
│ └── entrypoint.sh
|
|
239
|
+
└── pyproject.toml
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The package uses a sub-module hierarchy (`web/`) to support future extensions (e.g. `internal/` search) that can be deployed as separate containers from the same package.
|
|
243
|
+
|
|
244
|
+
## Architecture
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
248
|
+
│ FastAPI App │
|
|
249
|
+
│ /search endpoint │
|
|
250
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
251
|
+
│
|
|
252
|
+
┌─────▼─────┐
|
|
253
|
+
│ Factory │
|
|
254
|
+
└─────┬─────┘
|
|
255
|
+
│
|
|
256
|
+
┌───────────────┼───────────────┐
|
|
257
|
+
│ │
|
|
258
|
+
┌─────▼─────┐ ┌─────▼─────┐
|
|
259
|
+
│ Google │ │ Vertex AI │
|
|
260
|
+
│ Search │ │ (Gemini) │
|
|
261
|
+
└───────────┘ └───────────┘
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The service uses a **factory pattern** to register and resolve search engines, making it easy to add new backends.
|
|
265
|
+
|
|
266
|
+
## Error Handling
|
|
267
|
+
|
|
268
|
+
All errors return a consistent format:
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"status": "failed",
|
|
273
|
+
"error": "Error description"
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
| Status Code | Description |
|
|
278
|
+
|-------------|-------------|
|
|
279
|
+
| 400 | Validation error (invalid request) |
|
|
280
|
+
| 500 | Internal server error |
|
|
281
|
+
|
|
282
|
+
## Production Deployment
|
|
283
|
+
|
|
284
|
+
The service includes a production-ready `deploy/entrypoint.sh` that uses Uvicorn:
|
|
285
|
+
|
|
286
|
+
| Variable | Default | Description |
|
|
287
|
+
|----------|---------|-------------|
|
|
288
|
+
| `HOST` | `0.0.0.0` | Bind address |
|
|
289
|
+
| `PORT` | `8080` | Listen port |
|
|
290
|
+
| `WORKERS` | `4` | Uvicorn workers |
|
|
291
|
+
| `TIMEOUT` | `120` | Keep-alive timeout |
|
|
292
|
+
| `LOG_LEVEL` | `info` | Logging verbosity |
|
|
293
|
+
|
|
294
|
+
## Development
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Run with hot reload
|
|
298
|
+
uv run uvicorn unique_search_proxy.web.app:app --reload --port 2349
|
|
299
|
+
|
|
300
|
+
# Format code
|
|
301
|
+
uv run ruff format .
|
|
302
|
+
|
|
303
|
+
# Lint
|
|
304
|
+
uv run ruff check .
|
|
305
|
+
|
|
306
|
+
# Run tests
|
|
307
|
+
uv run pytest
|
|
308
|
+
|
|
309
|
+
# Type check
|
|
310
|
+
uv run basedpyright
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
Proprietary - Unique AG
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Unique Search Proxy
|
|
2
|
+
|
|
3
|
+
A unified web search proxy API that provides a consistent interface for multiple search backends. Built with FastAPI and designed for seamless integration with AI applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This service acts as an abstraction layer over different search providers, allowing clients to switch between search engines without changing their integration code. Currently supports:
|
|
8
|
+
|
|
9
|
+
| Engine | Description |
|
|
10
|
+
|--------|-------------|
|
|
11
|
+
| **Google Custom Search** | Direct integration with Google's Custom Search JSON API |
|
|
12
|
+
| **Vertex AI (Gemini)** | AI-powered search using Google's Gemini models with grounding capabilities |
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### Prerequisites
|
|
17
|
+
|
|
18
|
+
- Python 3.12+
|
|
19
|
+
- uv for dependency management
|
|
20
|
+
- Google Cloud credentials (for Vertex AI)
|
|
21
|
+
- Google Custom Search API key and Engine ID (for Google Search)
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Install dependencies
|
|
27
|
+
uv sync
|
|
28
|
+
|
|
29
|
+
# Copy and configure environment variables
|
|
30
|
+
cp .env.example .env
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Environment Variables
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Google Custom Search
|
|
37
|
+
GOOGLE_SEARCH_API_KEY=your-api-key
|
|
38
|
+
GOOGLE_SEARCH_API_ENDPOINT=https://www.googleapis.com/customsearch/v1
|
|
39
|
+
GOOGLE_SEARCH_ENGINE_ID=your-engine-id
|
|
40
|
+
|
|
41
|
+
# Vertex AI
|
|
42
|
+
VERTEXAI_SERVICE_ACCOUNT_CREDENTIALS=path/to/credentials.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Running the Service
|
|
46
|
+
|
|
47
|
+
**Development:**
|
|
48
|
+
```bash
|
|
49
|
+
uv run python -m unique_search_proxy.web.app
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Docker (from published package — hash-verified):**
|
|
53
|
+
|
|
54
|
+
CI generates a hash-pinned `requirements.txt` from `uv.lock` and passes it into the
|
|
55
|
+
Docker build. Dependencies are installed with `--require-hashes`, then the package
|
|
56
|
+
itself is installed with `--no-deps`. To reproduce locally:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv export --locked --package unique-search-proxy --no-dev --no-emit-project \
|
|
60
|
+
-o deploy/requirements.txt
|
|
61
|
+
docker build --build-arg PACKAGE_VERSION=0.2.0 -t search-proxy deploy/
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Every transitive dependency is verified against its sha256 hash from the lockfile.
|
|
65
|
+
|
|
66
|
+
**Docker (from local source — no registry required):**
|
|
67
|
+
|
|
68
|
+
Build a wheel first, copy it into `deploy/`, then reference it:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv build --wheel --out-dir deploy/
|
|
72
|
+
docker build \
|
|
73
|
+
--build-arg LOCAL_WHEEL=unique_search_proxy-0.2.0-py3-none-any.whl \
|
|
74
|
+
-t search-proxy deploy/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Running the container:**
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker run --rm -p 8080:8080 search-proxy
|
|
81
|
+
|
|
82
|
+
# With custom environment variables
|
|
83
|
+
docker run --rm -p 8080:8080 -e WORKERS=8 -e LOG_LEVEL=debug search-proxy
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API Documentation
|
|
87
|
+
|
|
88
|
+
FastAPI provides automatic interactive API documentation:
|
|
89
|
+
|
|
90
|
+
| URL | Description |
|
|
91
|
+
|-----|-------------|
|
|
92
|
+
| `/docs` | Swagger UI - interactive API explorer |
|
|
93
|
+
| `/redoc` | ReDoc - alternative documentation |
|
|
94
|
+
| `/openapi.json` | OpenAPI schema |
|
|
95
|
+
|
|
96
|
+
## API Reference
|
|
97
|
+
|
|
98
|
+
### Health Check
|
|
99
|
+
|
|
100
|
+
```http
|
|
101
|
+
GET /health
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Response:**
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"status": "healthy"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Search
|
|
114
|
+
|
|
115
|
+
```http
|
|
116
|
+
POST /search
|
|
117
|
+
Content-Type: application/json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Request Body:**
|
|
121
|
+
|
|
122
|
+
| Field | Type | Required | Description |
|
|
123
|
+
|-------|------|----------|-------------|
|
|
124
|
+
| `search_engine` | string | No | `"google"` or `"vertexai"` (default: `"google"`) |
|
|
125
|
+
| `query` | string | Yes | The search query |
|
|
126
|
+
| `kwargs` | object | No | Engine-specific parameters |
|
|
127
|
+
|
|
128
|
+
**Response:**
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"results": [
|
|
132
|
+
{
|
|
133
|
+
"url": "https://example.com/article",
|
|
134
|
+
"title": "Article Title",
|
|
135
|
+
"snippet": "A brief description of the content...",
|
|
136
|
+
"content": ""
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Search Engine Configuration
|
|
145
|
+
|
|
146
|
+
### Google Custom Search
|
|
147
|
+
|
|
148
|
+
Uses Google's Custom Search JSON API for traditional web search results.
|
|
149
|
+
|
|
150
|
+
**Parameters (`kwargs`):**
|
|
151
|
+
|
|
152
|
+
| Parameter | Type | Default | Description |
|
|
153
|
+
|-----------|------|---------|-------------|
|
|
154
|
+
| `cx` | string | env default | Custom Search Engine ID (overrides env) |
|
|
155
|
+
| `fetchSize` | int | 10 | Number of results to fetch |
|
|
156
|
+
| `timeout` | int | 10 | Request timeout in seconds |
|
|
157
|
+
|
|
158
|
+
**Example:**
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"search_engine": "google",
|
|
162
|
+
"query": "latest AI developments",
|
|
163
|
+
"kwargs": {
|
|
164
|
+
"fetchSize": 20,
|
|
165
|
+
"timeout": 15
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Vertex AI (Gemini)
|
|
173
|
+
|
|
174
|
+
Leverages Google's Gemini models with web grounding for AI-enhanced search results. This engine:
|
|
175
|
+
|
|
176
|
+
1. Uses Gemini to search and synthesize information from the web
|
|
177
|
+
2. Generates structured results with citations
|
|
178
|
+
3. Optionally resolves shortened/redirect URLs to final destinations
|
|
179
|
+
|
|
180
|
+
**Parameters (`kwargs`):**
|
|
181
|
+
|
|
182
|
+
| Parameter | Type | Default | Description |
|
|
183
|
+
|-----------|------|---------|-------------|
|
|
184
|
+
| `modelName` | string | `"gemini-2.5-flash"` | Gemini model to use |
|
|
185
|
+
| `entrepriseSearch` | bool | `false` | Use Enterprise Web Search |
|
|
186
|
+
| `systemInstruction` | string | (built-in) | Custom system prompt |
|
|
187
|
+
| `resolveUrls` | bool | `true` | Resolve redirect URLs |
|
|
188
|
+
|
|
189
|
+
**Example:**
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"search_engine": "vertexai",
|
|
193
|
+
"query": "Compare the top 3 cloud providers for ML workloads",
|
|
194
|
+
"kwargs": {
|
|
195
|
+
"modelName": "gemini-2.5-flash",
|
|
196
|
+
"resolveUrls": true
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Project Structure
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
connectors/unique_search_proxy/
|
|
207
|
+
├── unique_search_proxy/ # Python package (published to PyPI)
|
|
208
|
+
│ ├── __init__.py
|
|
209
|
+
│ └── web/ # Web search API sub-module
|
|
210
|
+
│ ├── __init__.py
|
|
211
|
+
│ ├── app.py # FastAPI application
|
|
212
|
+
│ ├── settings.py # Global settings
|
|
213
|
+
│ └── core/ # Search engine implementations
|
|
214
|
+
│ ├── schema.py # Shared schemas
|
|
215
|
+
│ ├── google_search/ # Google Custom Search backend
|
|
216
|
+
│ └── vertexai/ # Vertex AI (Gemini) backend
|
|
217
|
+
├── tests/ # Test suite
|
|
218
|
+
├── deploy/ # Container build artifacts
|
|
219
|
+
│ ├── Dockerfile # Hash-verified install or local wheel
|
|
220
|
+
│ └── entrypoint.sh
|
|
221
|
+
└── pyproject.toml
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The package uses a sub-module hierarchy (`web/`) to support future extensions (e.g. `internal/` search) that can be deployed as separate containers from the same package.
|
|
225
|
+
|
|
226
|
+
## Architecture
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
230
|
+
│ FastAPI App │
|
|
231
|
+
│ /search endpoint │
|
|
232
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
233
|
+
│
|
|
234
|
+
┌─────▼─────┐
|
|
235
|
+
│ Factory │
|
|
236
|
+
└─────┬─────┘
|
|
237
|
+
│
|
|
238
|
+
┌───────────────┼───────────────┐
|
|
239
|
+
│ │
|
|
240
|
+
┌─────▼─────┐ ┌─────▼─────┐
|
|
241
|
+
│ Google │ │ Vertex AI │
|
|
242
|
+
│ Search │ │ (Gemini) │
|
|
243
|
+
└───────────┘ └───────────┘
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The service uses a **factory pattern** to register and resolve search engines, making it easy to add new backends.
|
|
247
|
+
|
|
248
|
+
## Error Handling
|
|
249
|
+
|
|
250
|
+
All errors return a consistent format:
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"status": "failed",
|
|
255
|
+
"error": "Error description"
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
| Status Code | Description |
|
|
260
|
+
|-------------|-------------|
|
|
261
|
+
| 400 | Validation error (invalid request) |
|
|
262
|
+
| 500 | Internal server error |
|
|
263
|
+
|
|
264
|
+
## Production Deployment
|
|
265
|
+
|
|
266
|
+
The service includes a production-ready `deploy/entrypoint.sh` that uses Uvicorn:
|
|
267
|
+
|
|
268
|
+
| Variable | Default | Description |
|
|
269
|
+
|----------|---------|-------------|
|
|
270
|
+
| `HOST` | `0.0.0.0` | Bind address |
|
|
271
|
+
| `PORT` | `8080` | Listen port |
|
|
272
|
+
| `WORKERS` | `4` | Uvicorn workers |
|
|
273
|
+
| `TIMEOUT` | `120` | Keep-alive timeout |
|
|
274
|
+
| `LOG_LEVEL` | `info` | Logging verbosity |
|
|
275
|
+
|
|
276
|
+
## Development
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Run with hot reload
|
|
280
|
+
uv run uvicorn unique_search_proxy.web.app:app --reload --port 2349
|
|
281
|
+
|
|
282
|
+
# Format code
|
|
283
|
+
uv run ruff format .
|
|
284
|
+
|
|
285
|
+
# Lint
|
|
286
|
+
uv run ruff check .
|
|
287
|
+
|
|
288
|
+
# Run tests
|
|
289
|
+
uv run pytest
|
|
290
|
+
|
|
291
|
+
# Type check
|
|
292
|
+
uv run basedpyright
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## License
|
|
296
|
+
|
|
297
|
+
Proprietary - Unique AG
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "unique-search-proxy"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Web Search Proxy implementation"
|
|
5
|
+
authors = [{ name = "ThePhilAz", email = "rami.azouz@philico.com" }]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"fastapi>=0.115.0,<1.0.0",
|
|
10
|
+
"uvicorn[standard]>=0.32.0,<1.0.0",
|
|
11
|
+
"google-cloud-aiplatform>=1.128.0,<2.0.0",
|
|
12
|
+
"google-auth>=2.43.0,<3.0.0",
|
|
13
|
+
"google-generativeai>=0.8.5,<0.9.0",
|
|
14
|
+
"pydantic>=2.12.5,<3.0.0",
|
|
15
|
+
"httpx>=0.28.0,<0.29.0",
|
|
16
|
+
"python-dotenv>=1.2.1,<2.0.0",
|
|
17
|
+
"pydantic-settings>=2.12.0,<3.0.0"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = []
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["uv_build>=0.7.19,<0.8"]
|
|
25
|
+
build-backend = "uv_build"
|
|
26
|
+
|
|
27
|
+
[tool.uv.build-backend]
|
|
28
|
+
module-root = "."
|
|
29
|
+
|
|
30
|
+
[tool.uv]
|
|
31
|
+
exclude-newer = "2 weeks"
|
|
32
|
+
|
|
33
|
+
[tool.ruff]
|
|
34
|
+
target-version = "py312"
|
|
35
|
+
|
|
36
|
+
[tool.ruff.lint]
|
|
37
|
+
extend-select = ["I"]
|
|
38
|
+
|
|
39
|
+
[tool.basedpyright]
|
|
40
|
+
typeCheckingMode = "standard"
|
|
41
|
+
include = ["unique_search_proxy"]
|
|
42
|
+
|
|
43
|
+
[tool.deptry]
|
|
44
|
+
known_first_party = ["unique_search_proxy"]
|
|
45
|
+
|
|
46
|
+
[tool.poe.tasks]
|
|
47
|
+
lint = "ruff check ."
|
|
48
|
+
lint-fix = "ruff check . --fix"
|
|
49
|
+
format = "ruff format ."
|
|
50
|
+
test = "pytest"
|
|
51
|
+
typecheck = "basedpyright"
|
|
52
|
+
depcheck = "deptry ."
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
asyncio_mode = "auto"
|
|
56
|
+
addopts = "--strict-markers --import-mode=importlib --cov=unique_search_proxy --cov-report=xml --cov-report=term-missing"
|
|
57
|
+
markers = [
|
|
58
|
+
"ai: AI-authored test",
|
|
59
|
+
]
|
|
60
|
+
|
|
File without changes
|
|
File without changes
|