unique-web-search 1.7.4__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_web_search-1.7.4/PKG-INFO +147 -0
- unique_web_search-1.7.4/README.md +115 -0
- unique_web_search-1.7.4/pyproject.toml +59 -0
- unique_web_search-1.7.4/src/unique_web_search/__init__.py +0 -0
- unique_web_search-1.7.4/src/unique_web_search/client_settings.py +202 -0
- unique_web_search-1.7.4/src/unique_web_search/config.py +181 -0
- unique_web_search-1.7.4/src/unique_web_search/prompts.py +45 -0
- unique_web_search-1.7.4/src/unique_web_search/schema.py +50 -0
- unique_web_search-1.7.4/src/unique_web_search/service.py +239 -0
- unique_web_search-1.7.4/src/unique_web_search/services/client/proxy_config.py +119 -0
- unique_web_search-1.7.4/src/unique_web_search/services/content_processing/__init__.py +15 -0
- unique_web_search-1.7.4/src/unique_web_search/services/content_processing/config.py +94 -0
- unique_web_search-1.7.4/src/unique_web_search/services/content_processing/service.py +243 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/README.md +349 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/__init__.py +107 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/base.py +54 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/basic.py +119 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/crawl4ai.py +260 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/firecrawl.py +48 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/jina.py +103 -0
- unique_web_search-1.7.4/src/unique_web_search/services/crawlers/tavily.py +85 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/README.md +222 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/__init__.py +8 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/base_executor.py +156 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/configs/__init__.py +32 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/configs/base.py +26 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/configs/prompts.py +201 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/configs/v1_config.py +78 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/configs/v2_config.py +35 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/web_search_v1_executor.py +335 -0
- unique_web_search-1.7.4/src/unique_web_search/services/executors/web_search_v2_executor.py +288 -0
- unique_web_search-1.7.4/src/unique_web_search/services/helpers.py +18 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/README.md +707 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/__init__.py +149 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/base.py +78 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/bing.py +119 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/brave.py +122 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/custom_api.py +130 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/firecrawl.py +142 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/google.py +159 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/jina.py +285 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/schema.py +41 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/tavily.py +151 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/bing/__init__.py +13 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/bing/identity.py +49 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/bing/project.py +21 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/google/schema.py +233 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/__init__.py +31 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/client.py +40 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/config.py +32 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/exceptions.py +25 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/gemini.py +24 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/prompts.py +28 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/utils/vertexai/response_handler.py +87 -0
- unique_web_search-1.7.4/src/unique_web_search/services/search_engine/vertexai.py +124 -0
- unique_web_search-1.7.4/src/unique_web_search/settings.py +187 -0
- unique_web_search-1.7.4/src/unique_web_search/utils.py +128 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: unique-web-search
|
|
3
|
+
Version: 1.7.4
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Andreas Hauri, Gustav Hartz, Rami Azouz
|
|
6
|
+
Author-email: Andreas Hauri <andreas@unique.ch>, Gustav Hartz <gustav.hartz.ext@unique.ch>, Rami Azouz <rami.ext@unique.ch>
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Requires-Dist: typing-extensions>=4.14.1,<5
|
|
9
|
+
Requires-Dist: pydantic>=2.12.3,<3
|
|
10
|
+
Requires-Dist: pydantic-settings>=2.10.1,<3
|
|
11
|
+
Requires-Dist: timeout-decorator>=0.5.0,<1
|
|
12
|
+
Requires-Dist: markdownify>=0.14.1,<1
|
|
13
|
+
Requires-Dist: fake-useragent>=2.2.0,<3
|
|
14
|
+
Requires-Dist: crawl4ai>=0.6.3,<1
|
|
15
|
+
Requires-Dist: firecrawl>=3.3.2,<4
|
|
16
|
+
Requires-Dist: tavily-python>=0.7.11,<1
|
|
17
|
+
Requires-Dist: unidecode>=1.4.0,<2
|
|
18
|
+
Requires-Dist: azure-ai-projects>=1.0.0,<2
|
|
19
|
+
Requires-Dist: azure-identity>=1.25.0,<2
|
|
20
|
+
Requires-Dist: unique-toolkit>=1.38.3,<2
|
|
21
|
+
Requires-Dist: azure-core>=1.36.0,<2
|
|
22
|
+
Requires-Dist: google-cloud-aiplatform>=1.128.0,<2
|
|
23
|
+
Requires-Dist: google-auth>=2.43.0,<3
|
|
24
|
+
Requires-Dist: google-generativeai>=0.8.5,<0.9
|
|
25
|
+
Requires-Dist: langchain-text-splitters>=1.0.0,<2
|
|
26
|
+
Requires-Dist: httpx>=0.28.1
|
|
27
|
+
Requires-Dist: tiktoken>=0.12.0
|
|
28
|
+
Requires-Dist: openai>=1.109.1
|
|
29
|
+
Requires-Dist: certifi>=2025.11.12
|
|
30
|
+
Requires-Python: >=3.12
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Unique Web Search
|
|
34
|
+
|
|
35
|
+
A powerful, configurable web search tool for retrieving and processing the latest information from the internet. This package provides intelligent search capabilities with support for multiple search engines, web crawlers, and content processing strategies.
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
The following diagram illustrates the complete architecture and workflow of the unique_web_search package:
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
## Key Features
|
|
44
|
+
|
|
45
|
+
- **Dual Execution Modes**:
|
|
46
|
+
- **V1 (Traditional)**: Query refinement with single or multiple search strategies
|
|
47
|
+
- **V2 (Step-based Planning)**: Advanced research planning with parallel execution
|
|
48
|
+
|
|
49
|
+
- **Multiple Search Engines**:
|
|
50
|
+
- Google Search
|
|
51
|
+
- Bing Search
|
|
52
|
+
- Brave Search
|
|
53
|
+
- Jina Search
|
|
54
|
+
- Tavily Search
|
|
55
|
+
- Firecrawl Search
|
|
56
|
+
- VertexAI (Gemini with Grounding)
|
|
57
|
+
- Custom API (integrate any compatible web search API)
|
|
58
|
+
|
|
59
|
+
- **Multiple Web Crawlers**:
|
|
60
|
+
- Basic HTTP Crawler
|
|
61
|
+
- Crawl4AI
|
|
62
|
+
- Jina Reader
|
|
63
|
+
- Tavily Crawler
|
|
64
|
+
- Firecrawl Crawler
|
|
65
|
+
|
|
66
|
+
- **Intelligent Content Processing**:
|
|
67
|
+
- LLM-based summarization
|
|
68
|
+
- Token-based truncation
|
|
69
|
+
- Relevancy scoring and sorting
|
|
70
|
+
- Content chunking and optimization
|
|
71
|
+
|
|
72
|
+
- **Query Refinement**:
|
|
73
|
+
- **BASIC Mode**: Single optimized search query
|
|
74
|
+
- **ADVANCED Mode**: Multiple targeted search queries for complex research
|
|
75
|
+
|
|
76
|
+
- **Performance Optimized**:
|
|
77
|
+
- Parallel execution of search and crawl operations
|
|
78
|
+
- Token limit management
|
|
79
|
+
- Configurable timeouts and error handling
|
|
80
|
+
|
|
81
|
+
## Detailed Subsystem Docs
|
|
82
|
+
|
|
83
|
+
For deeper dives into each subsystem, see the dedicated READMEs:
|
|
84
|
+
|
|
85
|
+
- [Search Engines](./unique_web_search/services/search_engine/README.md) — full catalogue of supported engines, configuration, and usage examples.
|
|
86
|
+
- [Crawlers](./unique_web_search/services/crawlers/README.md) — comparison of crawling strategies (Basic, Crawl4AI, Tavily, Firecrawl, Jina) with setup guides.
|
|
87
|
+
- [Executors](./unique_web_search/services/executors/README.md) — orchestration layer (V1 & V2) covering query refinement, planning, logging, and best practices.
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
The tool uses environment variables and configuration files to manage API keys and settings. Key configuration areas include:
|
|
92
|
+
|
|
93
|
+
- Search engine selection and API keys
|
|
94
|
+
- Crawler selection and configuration
|
|
95
|
+
- Content processing strategies (SUMMARIZE, TRUNCATE, NONE)
|
|
96
|
+
- Token limits and relevancy thresholds
|
|
97
|
+
- Proxy configuration
|
|
98
|
+
- Debug and monitoring options
|
|
99
|
+
|
|
100
|
+
## Dependency management (uv.lock + min/latest testing)
|
|
101
|
+
|
|
102
|
+
This package is a **library** and uses `uv` for dependency management.
|
|
103
|
+
|
|
104
|
+
We run tests additionally with minimal dependencies to ensure that the listed ranges are valid. NOTE: We use lowest-direct, not lowest.
|
|
105
|
+
Lowest attempts to use the lowest possible dependency versions _tarnsitively_ causing issues if a dependency has incorrect metadata. Example:
|
|
106
|
+
- google-cloud-aiplatform says it works with shapely<3.0.0.
|
|
107
|
+
- The lowest resolver assumes 1.0 which needs python 2 -> breaks
|
|
108
|
+
Therefore we use lowest-direct which only sets our direct dependencies to lowest. However, this only correctly verifies our min dependencies
|
|
109
|
+
if our code correctly lists all the required dependencies and never imports a transitive dependency. We therefore use deptry to ansure we
|
|
110
|
+
don't use transitive dependencies and that we have no unused dependencies.
|
|
111
|
+
|
|
112
|
+
### Test locally
|
|
113
|
+
|
|
114
|
+
- **Latest deps and deptry**:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
cd tool_packages/unique_web_search
|
|
118
|
+
uv sync
|
|
119
|
+
uv run pytest
|
|
120
|
+
uv run deptry
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
- **Min deps**:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
cd tool_packages/unique_web_search
|
|
129
|
+
uv venv
|
|
130
|
+
# Install runtime deps at minimum versions
|
|
131
|
+
uv pip install -e . --resolution=lowest-direct
|
|
132
|
+
# Install dev deps from [dependency-groups] (we only care about runtime dep minimums)
|
|
133
|
+
uv export --only-group dev --no-hashes | uv pip install -r -
|
|
134
|
+
# Use --no-sync to prevent uv from "fixing" the versions
|
|
135
|
+
uv run --no-sync pytest
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Workflow
|
|
139
|
+
|
|
140
|
+
1. **Input**: User query or structured search plan
|
|
141
|
+
2. **Configuration**: Load settings and initialize services
|
|
142
|
+
3. **Execution**:
|
|
143
|
+
- V1: Query refinement → Search → Crawl → Process
|
|
144
|
+
- V2: Execute planned steps in parallel → Process
|
|
145
|
+
4. **Content Processing**: Clean, summarize/truncate, and chunk content
|
|
146
|
+
5. **Optimization**: Reduce to token limits and sort by relevance
|
|
147
|
+
6. **Output**: Return structured content chunks optimized for LLM consumption
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Unique Web Search
|
|
2
|
+
|
|
3
|
+
A powerful, configurable web search tool for retrieving and processing the latest information from the internet. This package provides intelligent search capabilities with support for multiple search engines, web crawlers, and content processing strategies.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
The following diagram illustrates the complete architecture and workflow of the unique_web_search package:
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Key Features
|
|
12
|
+
|
|
13
|
+
- **Dual Execution Modes**:
|
|
14
|
+
- **V1 (Traditional)**: Query refinement with single or multiple search strategies
|
|
15
|
+
- **V2 (Step-based Planning)**: Advanced research planning with parallel execution
|
|
16
|
+
|
|
17
|
+
- **Multiple Search Engines**:
|
|
18
|
+
- Google Search
|
|
19
|
+
- Bing Search
|
|
20
|
+
- Brave Search
|
|
21
|
+
- Jina Search
|
|
22
|
+
- Tavily Search
|
|
23
|
+
- Firecrawl Search
|
|
24
|
+
- VertexAI (Gemini with Grounding)
|
|
25
|
+
- Custom API (integrate any compatible web search API)
|
|
26
|
+
|
|
27
|
+
- **Multiple Web Crawlers**:
|
|
28
|
+
- Basic HTTP Crawler
|
|
29
|
+
- Crawl4AI
|
|
30
|
+
- Jina Reader
|
|
31
|
+
- Tavily Crawler
|
|
32
|
+
- Firecrawl Crawler
|
|
33
|
+
|
|
34
|
+
- **Intelligent Content Processing**:
|
|
35
|
+
- LLM-based summarization
|
|
36
|
+
- Token-based truncation
|
|
37
|
+
- Relevancy scoring and sorting
|
|
38
|
+
- Content chunking and optimization
|
|
39
|
+
|
|
40
|
+
- **Query Refinement**:
|
|
41
|
+
- **BASIC Mode**: Single optimized search query
|
|
42
|
+
- **ADVANCED Mode**: Multiple targeted search queries for complex research
|
|
43
|
+
|
|
44
|
+
- **Performance Optimized**:
|
|
45
|
+
- Parallel execution of search and crawl operations
|
|
46
|
+
- Token limit management
|
|
47
|
+
- Configurable timeouts and error handling
|
|
48
|
+
|
|
49
|
+
## Detailed Subsystem Docs
|
|
50
|
+
|
|
51
|
+
For deeper dives into each subsystem, see the dedicated READMEs:
|
|
52
|
+
|
|
53
|
+
- [Search Engines](./unique_web_search/services/search_engine/README.md) — full catalogue of supported engines, configuration, and usage examples.
|
|
54
|
+
- [Crawlers](./unique_web_search/services/crawlers/README.md) — comparison of crawling strategies (Basic, Crawl4AI, Tavily, Firecrawl, Jina) with setup guides.
|
|
55
|
+
- [Executors](./unique_web_search/services/executors/README.md) — orchestration layer (V1 & V2) covering query refinement, planning, logging, and best practices.
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
The tool uses environment variables and configuration files to manage API keys and settings. Key configuration areas include:
|
|
60
|
+
|
|
61
|
+
- Search engine selection and API keys
|
|
62
|
+
- Crawler selection and configuration
|
|
63
|
+
- Content processing strategies (SUMMARIZE, TRUNCATE, NONE)
|
|
64
|
+
- Token limits and relevancy thresholds
|
|
65
|
+
- Proxy configuration
|
|
66
|
+
- Debug and monitoring options
|
|
67
|
+
|
|
68
|
+
## Dependency management (uv.lock + min/latest testing)
|
|
69
|
+
|
|
70
|
+
This package is a **library** and uses `uv` for dependency management.
|
|
71
|
+
|
|
72
|
+
We run tests additionally with minimal dependencies to ensure that the listed ranges are valid. NOTE: We use lowest-direct, not lowest.
|
|
73
|
+
Lowest attempts to use the lowest possible dependency versions _tarnsitively_ causing issues if a dependency has incorrect metadata. Example:
|
|
74
|
+
- google-cloud-aiplatform says it works with shapely<3.0.0.
|
|
75
|
+
- The lowest resolver assumes 1.0 which needs python 2 -> breaks
|
|
76
|
+
Therefore we use lowest-direct which only sets our direct dependencies to lowest. However, this only correctly verifies our min dependencies
|
|
77
|
+
if our code correctly lists all the required dependencies and never imports a transitive dependency. We therefore use deptry to ansure we
|
|
78
|
+
don't use transitive dependencies and that we have no unused dependencies.
|
|
79
|
+
|
|
80
|
+
### Test locally
|
|
81
|
+
|
|
82
|
+
- **Latest deps and deptry**:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cd tool_packages/unique_web_search
|
|
86
|
+
uv sync
|
|
87
|
+
uv run pytest
|
|
88
|
+
uv run deptry
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
- **Min deps**:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
cd tool_packages/unique_web_search
|
|
97
|
+
uv venv
|
|
98
|
+
# Install runtime deps at minimum versions
|
|
99
|
+
uv pip install -e . --resolution=lowest-direct
|
|
100
|
+
# Install dev deps from [dependency-groups] (we only care about runtime dep minimums)
|
|
101
|
+
uv export --only-group dev --no-hashes | uv pip install -r -
|
|
102
|
+
# Use --no-sync to prevent uv from "fixing" the versions
|
|
103
|
+
uv run --no-sync pytest
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Workflow
|
|
107
|
+
|
|
108
|
+
1. **Input**: User query or structured search plan
|
|
109
|
+
2. **Configuration**: Load settings and initialize services
|
|
110
|
+
3. **Execution**:
|
|
111
|
+
- V1: Query refinement → Search → Crawl → Process
|
|
112
|
+
- V2: Execute planned steps in parallel → Process
|
|
113
|
+
4. **Content Processing**: Clean, summarize/truncate, and chunk content
|
|
114
|
+
5. **Optimization**: Reduce to token limits and sort by relevance
|
|
115
|
+
6. **Output**: Return structured content chunks optimized for LLM consumption
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "unique_web_search"
|
|
3
|
+
version = "1.7.4"
|
|
4
|
+
description = ""
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Andreas Hauri", email = "andreas@unique.ch" },
|
|
9
|
+
{ name = "Gustav Hartz", email = "gustav.hartz.ext@unique.ch" },
|
|
10
|
+
{ name = "Rami Azouz", email = "rami.ext@unique.ch" },
|
|
11
|
+
]
|
|
12
|
+
license = { text = "Proprietary" }
|
|
13
|
+
dependencies = [
|
|
14
|
+
"typing-extensions>=4.14.1,<5",
|
|
15
|
+
"pydantic>=2.12.3,<3",
|
|
16
|
+
"pydantic-settings>=2.10.1,<3",
|
|
17
|
+
"timeout-decorator>=0.5.0,<1",
|
|
18
|
+
"markdownify>=0.14.1,<1",
|
|
19
|
+
"fake-useragent>=2.2.0,<3",
|
|
20
|
+
"crawl4ai>=0.6.3,<1",
|
|
21
|
+
"firecrawl>=3.3.2,<4",
|
|
22
|
+
"tavily-python>=0.7.11,<1",
|
|
23
|
+
"unidecode>=1.4.0,<2",
|
|
24
|
+
"azure-ai-projects>=1.0.0,<2",
|
|
25
|
+
"azure-identity>=1.25.0,<2",
|
|
26
|
+
"unique-toolkit>=1.38.3,<2",
|
|
27
|
+
"azure-core>=1.36.0,<2",
|
|
28
|
+
"google-cloud-aiplatform>=1.128.0,<2",
|
|
29
|
+
"google-auth>=2.43.0,<3",
|
|
30
|
+
"google-generativeai>=0.8.5,<0.9",
|
|
31
|
+
"langchain-text-splitters>=1.0.0,<2",
|
|
32
|
+
"httpx>=0.28.1",
|
|
33
|
+
"tiktoken>=0.12.0",
|
|
34
|
+
"openai>=1.109.1",
|
|
35
|
+
"certifi>=2025.11.12",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["uv_build>=0.8.14,<0.9.0"]
|
|
40
|
+
build-backend = "uv_build"
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"deptry>=0.24.0",
|
|
45
|
+
"pytest>=8.4.1,<9",
|
|
46
|
+
"pytest-asyncio>=1.2.0,<2",
|
|
47
|
+
"pytest-mock>=3.14.0,<4",
|
|
48
|
+
"ruff>=0.12.10,<0.13",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.deptry]
|
|
52
|
+
known_first_party = ["unique_web_search"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
target-version = "py312"
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
extend-select = ["I"]
|
|
59
|
+
|
|
File without changes
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from unique_web_search.settings import env_settings
|
|
6
|
+
|
|
7
|
+
_LOGGER = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GoogleSearchSettings(BaseModel):
|
|
11
|
+
api_key: str | None = None
|
|
12
|
+
search_engine_id: str | None = None
|
|
13
|
+
api_endpoint: str | None = None
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def is_configured(self) -> bool:
|
|
17
|
+
return (
|
|
18
|
+
self.api_key and self.search_engine_id and self.api_endpoint
|
|
19
|
+
) is not None
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_env_settings(cls):
|
|
23
|
+
missing_settings = []
|
|
24
|
+
|
|
25
|
+
if env_settings.google_search_api_key is None:
|
|
26
|
+
missing_settings.append("API Key")
|
|
27
|
+
if env_settings.google_search_engine_id is None:
|
|
28
|
+
missing_settings.append("Engine ID")
|
|
29
|
+
if env_settings.google_search_api_endpoint is None:
|
|
30
|
+
missing_settings.append("API Endpoint")
|
|
31
|
+
|
|
32
|
+
if missing_settings:
|
|
33
|
+
_LOGGER.warning(
|
|
34
|
+
f"Google Search API missing required settings: {', '.join(missing_settings)}"
|
|
35
|
+
)
|
|
36
|
+
else:
|
|
37
|
+
_LOGGER.info("Google Search API is properly configured")
|
|
38
|
+
|
|
39
|
+
return cls(
|
|
40
|
+
api_key=env_settings.google_search_api_key,
|
|
41
|
+
search_engine_id=env_settings.google_search_engine_id,
|
|
42
|
+
api_endpoint=env_settings.google_search_api_endpoint,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
_google_search_settings: GoogleSearchSettings | None = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_google_search_settings() -> GoogleSearchSettings:
|
|
50
|
+
global _google_search_settings
|
|
51
|
+
if _google_search_settings is None:
|
|
52
|
+
_google_search_settings = GoogleSearchSettings.from_env_settings()
|
|
53
|
+
return _google_search_settings
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class FirecrawlSearchSettings(BaseModel):
|
|
57
|
+
api_key: str | None = None
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def is_configured(self) -> bool:
|
|
61
|
+
return self.api_key is not None
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def from_env_settings(cls):
|
|
65
|
+
missing_settings = []
|
|
66
|
+
|
|
67
|
+
if env_settings.firecrawl_api_key is None:
|
|
68
|
+
missing_settings.append("API Key")
|
|
69
|
+
|
|
70
|
+
if missing_settings:
|
|
71
|
+
_LOGGER.warning(
|
|
72
|
+
f"Firecrawl Search API missing required settings: {', '.join(missing_settings)}"
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
_LOGGER.info("Firecrawl Search API is properly configured")
|
|
76
|
+
|
|
77
|
+
return cls(
|
|
78
|
+
api_key=env_settings.firecrawl_api_key,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
_firecrawl_search_settings: FirecrawlSearchSettings | None = None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_firecrawl_search_settings() -> FirecrawlSearchSettings:
|
|
86
|
+
global _firecrawl_search_settings
|
|
87
|
+
if _firecrawl_search_settings is None:
|
|
88
|
+
_firecrawl_search_settings = FirecrawlSearchSettings.from_env_settings()
|
|
89
|
+
return _firecrawl_search_settings
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class JinaSearchSettings(BaseModel):
|
|
93
|
+
api_key: str | None = None
|
|
94
|
+
search_api_endpoint: str = env_settings.jina_search_api_endpoint
|
|
95
|
+
reader_api_endpoint: str = env_settings.jina_reader_api_endpoint
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def is_configured(self) -> bool:
|
|
99
|
+
return self.api_key is not None
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def from_env_settings(cls):
|
|
103
|
+
missing_settings = []
|
|
104
|
+
|
|
105
|
+
if env_settings.jina_api_key is None:
|
|
106
|
+
missing_settings.append("API Key")
|
|
107
|
+
|
|
108
|
+
if missing_settings:
|
|
109
|
+
_LOGGER.warning(
|
|
110
|
+
f"Jina Search API missing required settings: {', '.join(missing_settings)}"
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
_LOGGER.info("Jina Search API is properly configured")
|
|
114
|
+
|
|
115
|
+
return cls(
|
|
116
|
+
api_key=env_settings.jina_api_key,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
_jina_search_settings: JinaSearchSettings | None = None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def get_jina_search_settings() -> JinaSearchSettings:
|
|
124
|
+
global _jina_search_settings
|
|
125
|
+
if _jina_search_settings is None:
|
|
126
|
+
_jina_search_settings = JinaSearchSettings.from_env_settings()
|
|
127
|
+
return _jina_search_settings
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class TavilySearchSettings(BaseModel):
|
|
131
|
+
api_key: str | None = None
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def is_configured(self) -> bool:
|
|
135
|
+
return self.api_key is not None
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def from_env_settings(cls):
|
|
139
|
+
missing_settings = []
|
|
140
|
+
|
|
141
|
+
if env_settings.tavily_api_key is None:
|
|
142
|
+
missing_settings.append("API Key")
|
|
143
|
+
|
|
144
|
+
if missing_settings:
|
|
145
|
+
_LOGGER.warning(
|
|
146
|
+
f"Tavily Search API missing required settings: {', '.join(missing_settings)}"
|
|
147
|
+
)
|
|
148
|
+
else:
|
|
149
|
+
_LOGGER.info("Tavily Search API is properly configured")
|
|
150
|
+
|
|
151
|
+
return cls(api_key=env_settings.tavily_api_key)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
_tavily_search_settings: TavilySearchSettings | None = None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_tavily_search_settings() -> TavilySearchSettings:
|
|
158
|
+
global _tavily_search_settings
|
|
159
|
+
if _tavily_search_settings is None:
|
|
160
|
+
_tavily_search_settings = TavilySearchSettings.from_env_settings()
|
|
161
|
+
return _tavily_search_settings
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class BraveSearchSettings(BaseModel):
|
|
165
|
+
api_key: str | None = None
|
|
166
|
+
api_endpoint: str | None = None
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def is_configured(self) -> bool:
|
|
170
|
+
return self.api_key is not None
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def from_env_settings(cls):
|
|
174
|
+
missing_settings = []
|
|
175
|
+
|
|
176
|
+
if env_settings.brave_search_api_key is None:
|
|
177
|
+
missing_settings.append("API Key")
|
|
178
|
+
if env_settings.brave_search_api_endpoint is None:
|
|
179
|
+
missing_settings.append("API Endpoint")
|
|
180
|
+
|
|
181
|
+
if missing_settings:
|
|
182
|
+
_LOGGER.warning(
|
|
183
|
+
f"Brave Search API missing required settings: {', '.join(missing_settings)}"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
else:
|
|
187
|
+
_LOGGER.info("Brave Search API is properly configured")
|
|
188
|
+
|
|
189
|
+
return cls(
|
|
190
|
+
api_key=env_settings.brave_search_api_key,
|
|
191
|
+
api_endpoint=env_settings.brave_search_api_endpoint,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
_brave_search_settings: BraveSearchSettings | None = None
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def get_brave_search_settings() -> BraveSearchSettings:
|
|
199
|
+
global _brave_search_settings
|
|
200
|
+
if _brave_search_settings is None:
|
|
201
|
+
_brave_search_settings = BraveSearchSettings.from_env_settings()
|
|
202
|
+
return _brave_search_settings
|