unique-web-search 2026.26.0.dev0__tar.gz → 2026.26.0.dev2__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-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/PKG-INFO +4 -2
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/pyproject.toml +6 -2
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/client_settings.py +27 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/__init__.py +16 -1
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/base.py +1 -1
- unique_web_search-2026.26.0.dev2/src/unique_web_search/services/crawlers/basic_proxy.py +79 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/settings.py +4 -1
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/README.md +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/prompts.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/service.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/argument_screening/service.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/crawl4ai.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/dns.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/models.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/netloc.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/policy.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/redirect.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/resolver.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/service.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/url_safety/settings.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/base_config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/base_executor.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/executor.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/prompts/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/prompts/restrict_date_description.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v1/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/executor.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/prompts/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v2/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/config.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/executor.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/prompts/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/executors/v3/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/message_log.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/README.md +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/base.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/bing.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/brave.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/custom_api.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/firecrawl.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/google.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/jina.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/perplexity.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/tavily.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/search_engine/vertexai.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/snippet_judge/service.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/services/structured_llm.py +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/skills/web-search-v3.md +0 -0
- {unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-web-search
|
|
3
|
-
Version: 2026.26.0.
|
|
3
|
+
Version: 2026.26.0.dev2
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Andreas Hauri, Gustav Hartz, Rami Azouz
|
|
6
6
|
Author-email: Andreas Hauri <andreas@unique.ch>, Gustav Hartz <gustav.hartz.ext@unique.ch>, Rami Azouz <rami.ext@unique.ch>
|
|
@@ -17,7 +17,7 @@ Requires-Dist: tavily-python>=0.7.11,<1
|
|
|
17
17
|
Requires-Dist: unidecode>=1.4.0,<2
|
|
18
18
|
Requires-Dist: azure-ai-projects>=1.0.0,<2
|
|
19
19
|
Requires-Dist: azure-identity>=1.25.0,<2
|
|
20
|
-
Requires-Dist: unique-toolkit[monitoring]>=2026.26.0.
|
|
20
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.26.0.dev2,<2026.26.0rc0
|
|
21
21
|
Requires-Dist: azure-core>=1.36.0,<2
|
|
22
22
|
Requires-Dist: google-cloud-aiplatform>=1.128.0,<2
|
|
23
23
|
Requires-Dist: google-auth>=2.43.0,<3
|
|
@@ -28,6 +28,8 @@ Requires-Dist: certifi>=2025.11.12
|
|
|
28
28
|
Requires-Dist: jinja2>=3.1.6
|
|
29
29
|
Requires-Dist: playwright>=1.58.0
|
|
30
30
|
Requires-Dist: perplexityai>=0.34.0
|
|
31
|
+
Requires-Dist: unique-search-proxy-core>=2026.26.0.dev1,<2026.26.0rc0
|
|
32
|
+
Requires-Dist: unique-search-proxy-sdk>=2026.26.0.dev1,<2026.26.0rc0
|
|
31
33
|
Requires-Python: >=3.12, <4.0
|
|
32
34
|
Description-Content-Type: text/markdown
|
|
33
35
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_web_search"
|
|
3
|
-
version = "2026.26.0.
|
|
3
|
+
version = "2026.26.0.dev2"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<4.0"
|
|
@@ -23,7 +23,7 @@ dependencies = [
|
|
|
23
23
|
"unidecode>=1.4.0,<2",
|
|
24
24
|
"azure-ai-projects>=1.0.0,<2",
|
|
25
25
|
"azure-identity>=1.25.0,<2",
|
|
26
|
-
"unique-toolkit[monitoring]>=2026.26.0.
|
|
26
|
+
"unique-toolkit[monitoring]>=2026.26.0.dev2,<2026.26.0rc0",
|
|
27
27
|
"azure-core>=1.36.0,<2",
|
|
28
28
|
"google-cloud-aiplatform>=1.128.0,<2",
|
|
29
29
|
"google-auth>=2.43.0,<3",
|
|
@@ -34,6 +34,8 @@ dependencies = [
|
|
|
34
34
|
"jinja2>=3.1.6",
|
|
35
35
|
"playwright>=1.58.0",
|
|
36
36
|
"perplexityai>=0.34.0",
|
|
37
|
+
"unique-search-proxy-core>=2026.26.0.dev1,<2026.26.0rc0",
|
|
38
|
+
"unique-search-proxy-sdk>=2026.26.0.dev1,<2026.26.0rc0",
|
|
37
39
|
]
|
|
38
40
|
|
|
39
41
|
[build-system]
|
|
@@ -91,3 +93,5 @@ extend-select = ["I"]
|
|
|
91
93
|
|
|
92
94
|
[tool.uv.sources]
|
|
93
95
|
unique-toolkit = { workspace = true }
|
|
96
|
+
unique-search-proxy-sdk = { workspace = true }
|
|
97
|
+
unique-search-proxy-core = { workspace = true }
|
|
@@ -235,3 +235,30 @@ def get_perplexity_search_settings() -> PerplexitySearchSettings:
|
|
|
235
235
|
if _perplexity_search_settings is None:
|
|
236
236
|
_perplexity_search_settings = PerplexitySearchSettings.from_env_settings()
|
|
237
237
|
return _perplexity_search_settings
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class SearchProxySettings(BaseModel):
|
|
241
|
+
base_url: str | None = None
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def is_configured(self) -> bool:
|
|
245
|
+
return self.base_url is not None
|
|
246
|
+
|
|
247
|
+
@classmethod
|
|
248
|
+
def from_env_settings(cls):
|
|
249
|
+
if env_settings.search_proxy_base_url is None:
|
|
250
|
+
_LOGGER.warning("Unique Search Proxy missing required setting: Base URL")
|
|
251
|
+
else:
|
|
252
|
+
_LOGGER.info("Unique Search Proxy is properly configured")
|
|
253
|
+
|
|
254
|
+
return cls(base_url=env_settings.search_proxy_base_url)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
_search_proxy_settings: SearchProxySettings | None = None
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_search_proxy_settings() -> SearchProxySettings:
|
|
261
|
+
global _search_proxy_settings
|
|
262
|
+
if _search_proxy_settings is None:
|
|
263
|
+
_search_proxy_settings = SearchProxySettings.from_env_settings()
|
|
264
|
+
return _search_proxy_settings
|
|
@@ -9,6 +9,10 @@ from unique_web_search.services.crawlers.basic import (
|
|
|
9
9
|
BasicCrawler,
|
|
10
10
|
BasicCrawlerConfig,
|
|
11
11
|
)
|
|
12
|
+
from unique_web_search.services.crawlers.basic_proxy import (
|
|
13
|
+
BasicCrawlerProxyConfig,
|
|
14
|
+
BasicProxyCrawler,
|
|
15
|
+
)
|
|
12
16
|
from unique_web_search.services.crawlers.crawl4ai import (
|
|
13
17
|
Crawl4AiCrawler,
|
|
14
18
|
Crawl4AiCrawlerConfig,
|
|
@@ -27,11 +31,17 @@ from unique_web_search.services.crawlers.tavily import (
|
|
|
27
31
|
)
|
|
28
32
|
|
|
29
33
|
CrawlerTypes = (
|
|
30
|
-
BasicCrawler
|
|
34
|
+
BasicCrawler
|
|
35
|
+
| BasicProxyCrawler
|
|
36
|
+
| Crawl4AiCrawler
|
|
37
|
+
| FirecrawlCrawler
|
|
38
|
+
| JinaCrawler
|
|
39
|
+
| TavilyCrawler
|
|
31
40
|
)
|
|
32
41
|
|
|
33
42
|
CrawlerConfigTypes = (
|
|
34
43
|
BasicCrawlerConfig
|
|
44
|
+
| BasicCrawlerProxyConfig
|
|
35
45
|
| Crawl4AiCrawlerConfig
|
|
36
46
|
| FirecrawlCrawlerConfig
|
|
37
47
|
| JinaCrawlerConfig
|
|
@@ -44,6 +54,7 @@ CRAWLER_NAME_TO_CONFIG = {
|
|
|
44
54
|
"firecrawl": FirecrawlCrawlerConfig,
|
|
45
55
|
"jina": JinaCrawlerConfig,
|
|
46
56
|
"tavily": TavilyCrawlerConfig,
|
|
57
|
+
"basic_proxy": BasicCrawlerProxyConfig,
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
|
|
@@ -61,6 +72,8 @@ def get_crawler_service(
|
|
|
61
72
|
return FirecrawlCrawler(crawler_config)
|
|
62
73
|
case CrawlerType.JINA:
|
|
63
74
|
return JinaCrawler(crawler_config)
|
|
75
|
+
case CrawlerType.BASIC_PROXY:
|
|
76
|
+
return BasicProxyCrawler(crawler_config)
|
|
64
77
|
|
|
65
78
|
|
|
66
79
|
def get_crawler_config_types_from_names(crawler_names: list[str]) -> TypeAlias:
|
|
@@ -90,6 +103,8 @@ def get_default_crawler_config(
|
|
|
90
103
|
__all__ = [
|
|
91
104
|
"BasicCrawler",
|
|
92
105
|
"BasicCrawlerConfig",
|
|
106
|
+
"BasicProxyCrawler",
|
|
107
|
+
"BasicCrawlerProxyConfig",
|
|
93
108
|
"Crawl4AiCrawler",
|
|
94
109
|
"Crawl4AiCrawlerConfig",
|
|
95
110
|
"FirecrawlCrawler",
|
|
@@ -20,11 +20,11 @@ from unique_web_search.services.helpers import (
|
|
|
20
20
|
class CrawlerType(StrEnum):
|
|
21
21
|
CRAWL4AI = "Crawl4AiCrawler"
|
|
22
22
|
BASIC = "BasicCrawler"
|
|
23
|
+
BASIC_PROXY = "BasicProxyCrawler"
|
|
23
24
|
NO_CRAWLER = "NoCrawler"
|
|
24
25
|
TAVILY = "TavilyCrawler"
|
|
25
26
|
FIRECRAWL = "FirecrawlCrawler"
|
|
26
27
|
JINA = "JinaCrawler"
|
|
27
|
-
NONE = "None"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
T = TypeVar("T", bound=CrawlerType)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from unique_search_proxy_core.crawlers import (
|
|
5
|
+
BasicCrawlerConfig as BasicCrawlerProxyCoreConfig,
|
|
6
|
+
)
|
|
7
|
+
from unique_search_proxy_core.crawlers.base import CrawlerType as ProxyCrawlerType
|
|
8
|
+
from unique_search_proxy_sdk import UniqueSearchProxyClient
|
|
9
|
+
from unique_search_proxy_sdk._generated.models.crawl_url_result import CrawlUrlResult
|
|
10
|
+
from unique_search_proxy_sdk._generated.models.per_url_error import PerUrlError
|
|
11
|
+
|
|
12
|
+
from unique_web_search.client_settings import get_search_proxy_settings
|
|
13
|
+
from unique_web_search.services.crawlers.base import BaseCrawlerConfig, CrawlerType
|
|
14
|
+
|
|
15
|
+
_LOGGER = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BasicCrawlerProxyConfig(
|
|
19
|
+
BaseCrawlerConfig[CrawlerType.BASIC_PROXY], BasicCrawlerProxyCoreConfig
|
|
20
|
+
):
|
|
21
|
+
crawler_type: Literal[CrawlerType.BASIC_PROXY] = CrawlerType.BASIC_PROXY
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BasicProxyCrawler:
|
|
25
|
+
"""Crawler that delegates fetching to the remote Unique Search Proxy service.
|
|
26
|
+
|
|
27
|
+
Intermediate transition crawler: instead of fetching URLs in-process (see
|
|
28
|
+
:class:`BasicCrawler`), it forwards the request to the search-proxy service
|
|
29
|
+
via :class:`UniqueSearchProxyClient` and maps the per-URL results back to the
|
|
30
|
+
markdown list contract shared by the other crawlers.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, config: BasicCrawlerProxyConfig):
|
|
34
|
+
self.config: BasicCrawlerProxyConfig = config
|
|
35
|
+
|
|
36
|
+
async def crawl(self, urls: list[str]) -> list[str]:
|
|
37
|
+
return await self._crawl(urls)
|
|
38
|
+
|
|
39
|
+
async def _crawl(self, urls: list[str]) -> list[str]:
|
|
40
|
+
base_url = get_search_proxy_settings().base_url
|
|
41
|
+
assert base_url is not None, "Unique Search Proxy base URL is not configured"
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
async with UniqueSearchProxyClient(
|
|
45
|
+
base_url=base_url,
|
|
46
|
+
timeout=float(self.config.timeout),
|
|
47
|
+
) as client:
|
|
48
|
+
response = await client.crawl.crawl(
|
|
49
|
+
urls,
|
|
50
|
+
crawler_type=ProxyCrawlerType.BASIC,
|
|
51
|
+
content_types=self.config.content_types,
|
|
52
|
+
timeout=self.config.timeout,
|
|
53
|
+
max_concurrent_requests=self.config.max_concurrent_requests,
|
|
54
|
+
)
|
|
55
|
+
except Exception as error:
|
|
56
|
+
_LOGGER.exception("Unique Search Proxy crawl request failed")
|
|
57
|
+
return [f"Unable to crawl URL via search proxy: {error}" for _ in urls]
|
|
58
|
+
|
|
59
|
+
url_to_markdown = {
|
|
60
|
+
result.url: _result_to_markdown(result) for result in response.results
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return [
|
|
64
|
+
url_to_markdown.get(url, "Error: URL not found in search proxy response")
|
|
65
|
+
for url in urls
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _result_to_markdown(result: CrawlUrlResult) -> str:
|
|
70
|
+
if isinstance(result.content, str):
|
|
71
|
+
return result.content
|
|
72
|
+
|
|
73
|
+
if isinstance(result.error, PerUrlError):
|
|
74
|
+
return f"Error: {result.error.message}"
|
|
75
|
+
|
|
76
|
+
if isinstance(result.raw, str):
|
|
77
|
+
return result.raw
|
|
78
|
+
|
|
79
|
+
return "Error: No content returned by search proxy"
|
|
@@ -38,7 +38,10 @@ class Base(BaseSettings):
|
|
|
38
38
|
active_search_engines: list[str] = ["google"]
|
|
39
39
|
|
|
40
40
|
# Default Crawlers
|
|
41
|
-
active_inhouse_crawlers: list[str] = ["basic", "crawl4ai"]
|
|
41
|
+
active_inhouse_crawlers: list[str] = ["basic", "crawl4ai", "basic_proxy"]
|
|
42
|
+
|
|
43
|
+
# Unique Search Proxy service (used by the basic_proxy crawler)
|
|
44
|
+
search_proxy_base_url: str | None = None
|
|
42
45
|
|
|
43
46
|
# Google Search settings
|
|
44
47
|
google_search_api_key: str | None = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_web_search-2026.26.0.dev0 → unique_web_search-2026.26.0.dev2}/src/unique_web_search/utils.py
RENAMED
|
File without changes
|