unique_web_search 2026.24.0.dev2__tar.gz → 2026.24.0.dev3__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.24.0.dev2 → unique_web_search-2026.24.0.dev3}/PKG-INFO +2 -1
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/pyproject.toml +2 -1
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/client_settings.py +35 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/__init__.py +11 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/base.py +3 -0
- unique_web_search-2026.24.0.dev3/src/unique_web_search/services/search_engine/perplexity.py +121 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/settings.py +3 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/README.md +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/prompts.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/service.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/argument_screening/service.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/base.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/crawl4ai.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/dns.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/models.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/netloc.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/policy.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/redirect.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/resolver.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/service.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/url_safety/settings.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/base_config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/base_executor.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/executor.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/prompts/restrict_date_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v1/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/executor.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v2/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/config.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/executor.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/executors/v3/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/message_log.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/README.md +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/bing.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/brave.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/custom_api.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/firecrawl.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/google.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/jina.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/tavily.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/search_engine/vertexai.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/snippet_judge/service.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/services/structured_llm.py +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/skills/web-search-v3.md +0 -0
- {unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/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.24.0.
|
|
3
|
+
Version: 2026.24.0.dev3
|
|
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>
|
|
@@ -27,6 +27,7 @@ Requires-Dist: httpx>=0.28.1
|
|
|
27
27
|
Requires-Dist: certifi>=2025.11.12
|
|
28
28
|
Requires-Dist: jinja2>=3.1.6
|
|
29
29
|
Requires-Dist: playwright>=1.58.0
|
|
30
|
+
Requires-Dist: perplexityai>=0.34.0
|
|
30
31
|
Requires-Python: >=3.12, <4.0
|
|
31
32
|
Description-Content-Type: text/markdown
|
|
32
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_web_search"
|
|
3
|
-
version = "2026.24.0.
|
|
3
|
+
version = "2026.24.0.dev3"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<4.0"
|
|
@@ -33,6 +33,7 @@ dependencies = [
|
|
|
33
33
|
"certifi>=2025.11.12",
|
|
34
34
|
"jinja2>=3.1.6",
|
|
35
35
|
"playwright>=1.58.0",
|
|
36
|
+
"perplexityai>=0.34.0",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
[build-system]
|
|
@@ -200,3 +200,38 @@ def get_brave_search_settings() -> BraveSearchSettings:
|
|
|
200
200
|
if _brave_search_settings is None:
|
|
201
201
|
_brave_search_settings = BraveSearchSettings.from_env_settings()
|
|
202
202
|
return _brave_search_settings
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class PerplexitySearchSettings(BaseModel):
|
|
206
|
+
api_key: str | None = None
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def is_configured(self) -> bool:
|
|
210
|
+
return self.api_key is not None
|
|
211
|
+
|
|
212
|
+
@classmethod
|
|
213
|
+
def from_env_settings(cls):
|
|
214
|
+
missing_settings = []
|
|
215
|
+
|
|
216
|
+
if env_settings.perplexity_api_key is None:
|
|
217
|
+
missing_settings.append("API Key")
|
|
218
|
+
|
|
219
|
+
if missing_settings:
|
|
220
|
+
_LOGGER.warning(
|
|
221
|
+
"Perplexity Search API missing required settings: "
|
|
222
|
+
f"{', '.join(missing_settings)}"
|
|
223
|
+
)
|
|
224
|
+
else:
|
|
225
|
+
_LOGGER.info("Perplexity Search API is properly configured")
|
|
226
|
+
|
|
227
|
+
return cls(api_key=env_settings.perplexity_api_key)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
_perplexity_search_settings: PerplexitySearchSettings | None = None
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def get_perplexity_search_settings() -> PerplexitySearchSettings:
|
|
234
|
+
global _perplexity_search_settings
|
|
235
|
+
if _perplexity_search_settings is None:
|
|
236
|
+
_perplexity_search_settings = PerplexitySearchSettings.from_env_settings()
|
|
237
|
+
return _perplexity_search_settings
|
|
@@ -35,6 +35,10 @@ from unique_web_search.services.search_engine.jina import (
|
|
|
35
35
|
JinaConfig,
|
|
36
36
|
JinaSearch,
|
|
37
37
|
)
|
|
38
|
+
from unique_web_search.services.search_engine.perplexity import (
|
|
39
|
+
PerplexitySearch,
|
|
40
|
+
PerplexitySearchConfig,
|
|
41
|
+
)
|
|
38
42
|
from unique_web_search.services.search_engine.tavily import (
|
|
39
43
|
TavilyConfig,
|
|
40
44
|
TavilySearch,
|
|
@@ -51,6 +55,7 @@ SearchEngineTypes = (
|
|
|
51
55
|
| JinaSearch
|
|
52
56
|
| TavilySearch
|
|
53
57
|
| BraveSearch
|
|
58
|
+
| PerplexitySearch
|
|
54
59
|
| FireCrawlSearch
|
|
55
60
|
| VertexAI
|
|
56
61
|
)
|
|
@@ -61,6 +66,7 @@ SearchEngineConfigTypes = (
|
|
|
61
66
|
| JinaConfig
|
|
62
67
|
| TavilyConfig
|
|
63
68
|
| BraveSearchConfig
|
|
69
|
+
| PerplexitySearchConfig
|
|
64
70
|
| FireCrawlConfig
|
|
65
71
|
| VertexAIConfig
|
|
66
72
|
)
|
|
@@ -71,6 +77,7 @@ ENGINE_NAME_TO_CONFIG = {
|
|
|
71
77
|
"tavily": TavilyConfig,
|
|
72
78
|
"bing": BingSearchConfig,
|
|
73
79
|
"brave": BraveSearchConfig,
|
|
80
|
+
"perplexity": PerplexitySearchConfig,
|
|
74
81
|
"firecrawl": FireCrawlConfig,
|
|
75
82
|
"vertexai": VertexAIConfig,
|
|
76
83
|
"custom_api": CustomAPIConfig,
|
|
@@ -94,6 +101,8 @@ def get_search_engine_service(
|
|
|
94
101
|
return BingSearch(search_engine_config, language_model_service)
|
|
95
102
|
case SearchEngineType.BRAVE:
|
|
96
103
|
return BraveSearch(search_engine_config)
|
|
104
|
+
case SearchEngineType.PERPLEXITY:
|
|
105
|
+
return PerplexitySearch(search_engine_config)
|
|
97
106
|
case SearchEngineType.VERTEXAI:
|
|
98
107
|
return VertexAI(search_engine_config, language_model_service)
|
|
99
108
|
case SearchEngineType.CUSTOM_API:
|
|
@@ -140,6 +149,8 @@ __all__ = [
|
|
|
140
149
|
"BingSearch",
|
|
141
150
|
"BraveSearch",
|
|
142
151
|
"BraveSearchConfig",
|
|
152
|
+
"PerplexitySearch",
|
|
153
|
+
"PerplexitySearchConfig",
|
|
143
154
|
"get_search_engine_service",
|
|
144
155
|
"BaseSearchEngineConfig",
|
|
145
156
|
"SearchEngine",
|
|
@@ -21,6 +21,7 @@ class SearchEngineType(StrEnum):
|
|
|
21
21
|
FIRECRAWL = "Firecrawl"
|
|
22
22
|
TAVILY = "Tavily"
|
|
23
23
|
BRAVE = "Brave"
|
|
24
|
+
PERPLEXITY = "Perplexity"
|
|
24
25
|
BING = "Bing"
|
|
25
26
|
DUCKDUCKGO = "DuckDuckGo"
|
|
26
27
|
VERTEXAI = "VertexAI"
|
|
@@ -33,6 +34,7 @@ _SEARCH_ENGINE_MODE_MAP: dict[SearchEngineType, SearchEngineMode] = {
|
|
|
33
34
|
SearchEngineType.FIRECRAWL: SearchEngineMode.STANDARD,
|
|
34
35
|
SearchEngineType.TAVILY: SearchEngineMode.STANDARD,
|
|
35
36
|
SearchEngineType.BRAVE: SearchEngineMode.STANDARD,
|
|
37
|
+
SearchEngineType.PERPLEXITY: SearchEngineMode.STANDARD,
|
|
36
38
|
SearchEngineType.DUCKDUCKGO: SearchEngineMode.STANDARD,
|
|
37
39
|
SearchEngineType.BING: SearchEngineMode.AGENT,
|
|
38
40
|
SearchEngineType.VERTEXAI: SearchEngineMode.AGENT,
|
|
@@ -62,6 +64,7 @@ _SearchEngineExposedName = {
|
|
|
62
64
|
SearchEngineType.FIRECRAWL: "Firecrawl Search",
|
|
63
65
|
SearchEngineType.TAVILY: "Tavily Search",
|
|
64
66
|
SearchEngineType.BRAVE: "Brave Search",
|
|
67
|
+
SearchEngineType.PERPLEXITY: "Perplexity Search",
|
|
65
68
|
SearchEngineType.BING: "Grounding with Bing",
|
|
66
69
|
SearchEngineType.DUCKDUCKGO: "DuckDuckGo Search",
|
|
67
70
|
SearchEngineType.VERTEXAI: "Grounding with VertexAI",
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Annotated, Literal, TypeVar
|
|
3
|
+
|
|
4
|
+
from perplexity import AsyncPerplexity, Omit
|
|
5
|
+
from perplexity.types.search_create_response import Result
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
from unique_toolkit._common.pydantic_helpers import DeactivatedNone
|
|
8
|
+
|
|
9
|
+
from unique_web_search.client_settings import get_perplexity_search_settings
|
|
10
|
+
from unique_web_search.services.client.proxy_config import async_client
|
|
11
|
+
from unique_web_search.services.search_engine import (
|
|
12
|
+
BaseSearchEngineConfig,
|
|
13
|
+
SearchEngine,
|
|
14
|
+
SearchEngineType,
|
|
15
|
+
)
|
|
16
|
+
from unique_web_search.services.search_engine.base import get_search_engine_model_config
|
|
17
|
+
from unique_web_search.services.search_engine.schema import WebSearchResult
|
|
18
|
+
|
|
19
|
+
_LOGGER = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Perplexity Search API allows 1–20 results per request.
|
|
22
|
+
MAX_RESULTS_PER_REQUEST = 20
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PerplexitySearchConfig(BaseSearchEngineConfig[SearchEngineType.PERPLEXITY]):
|
|
26
|
+
model_config = get_search_engine_model_config(SearchEngineType.PERPLEXITY)
|
|
27
|
+
search_engine_name: Literal[SearchEngineType.PERPLEXITY] = (
|
|
28
|
+
SearchEngineType.PERPLEXITY
|
|
29
|
+
)
|
|
30
|
+
country: Annotated[str, Field(title="Active")] | DeactivatedNone = Field(
|
|
31
|
+
default=None,
|
|
32
|
+
description="The country to use for the search. It's a two-letter country code.",
|
|
33
|
+
)
|
|
34
|
+
max_tokens: Annotated[int, Field(title="Active")] | DeactivatedNone = Field(
|
|
35
|
+
default=None,
|
|
36
|
+
description="The maximum number of tokens to use for the context. It's a positive integer.",
|
|
37
|
+
)
|
|
38
|
+
search_mode: (
|
|
39
|
+
Annotated[Literal["web", "academic", "sec"], Field(title="Active")]
|
|
40
|
+
| DeactivatedNone
|
|
41
|
+
) = Field(
|
|
42
|
+
default=None,
|
|
43
|
+
description="The search mode to use for the search. It's a string.",
|
|
44
|
+
)
|
|
45
|
+
search_recency_filter: (
|
|
46
|
+
Annotated[
|
|
47
|
+
Literal["hour", "day", "week", "month", "year"], Field(title="Active")
|
|
48
|
+
]
|
|
49
|
+
| DeactivatedNone
|
|
50
|
+
) = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="The recency filter to use for the search. It's a string.",
|
|
53
|
+
)
|
|
54
|
+
search_type: (
|
|
55
|
+
Annotated[Literal["web", "people"], Field(title="Active")] | DeactivatedNone
|
|
56
|
+
) = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
description="The search type to use for the search. It's a string.",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
requires_scraping: bool = False
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class PerplexitySearch(SearchEngine[PerplexitySearchConfig]):
|
|
65
|
+
def __init__(self, *args, **kwargs):
|
|
66
|
+
super().__init__(*args, **kwargs)
|
|
67
|
+
self.is_configured = get_perplexity_search_settings().is_configured
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def requires_scraping(self) -> bool:
|
|
71
|
+
return self.config.requires_scraping
|
|
72
|
+
|
|
73
|
+
async def search(self, query: str, **kwargs) -> list[WebSearchResult]:
|
|
74
|
+
settings = get_perplexity_search_settings()
|
|
75
|
+
assert settings.is_configured
|
|
76
|
+
|
|
77
|
+
max_results = min(self.config.fetch_size, MAX_RESULTS_PER_REQUEST)
|
|
78
|
+
|
|
79
|
+
async with async_client() as http_client:
|
|
80
|
+
perplexity_client = AsyncPerplexity(
|
|
81
|
+
api_key=settings.api_key, http_client=http_client
|
|
82
|
+
)
|
|
83
|
+
response = await perplexity_client.search.create(
|
|
84
|
+
query=query,
|
|
85
|
+
max_results=max_results,
|
|
86
|
+
country=_return_omit_if_none(self.config.country),
|
|
87
|
+
max_tokens=_return_omit_if_none(self.config.max_tokens),
|
|
88
|
+
search_mode=_return_omit_if_none(self.config.search_mode),
|
|
89
|
+
search_recency_filter=_return_omit_if_none(
|
|
90
|
+
self.config.search_recency_filter
|
|
91
|
+
),
|
|
92
|
+
search_type=_return_omit_if_none(self.config.search_type),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return self._to_web_search_results(response.results)
|
|
96
|
+
|
|
97
|
+
def _to_web_search_results(
|
|
98
|
+
self, results: list[Result] | None
|
|
99
|
+
) -> list[WebSearchResult]:
|
|
100
|
+
if not results:
|
|
101
|
+
_LOGGER.warning("No search results found in Perplexity search response")
|
|
102
|
+
return []
|
|
103
|
+
|
|
104
|
+
return [
|
|
105
|
+
WebSearchResult(
|
|
106
|
+
url=result.url,
|
|
107
|
+
title=result.title,
|
|
108
|
+
snippet=result.snippet or "No Snippet Found",
|
|
109
|
+
)
|
|
110
|
+
for result in results
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
T = TypeVar("T")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _return_omit_if_none(value: T | None) -> T | Omit:
|
|
118
|
+
if value is None:
|
|
119
|
+
return Omit()
|
|
120
|
+
else:
|
|
121
|
+
return value
|
|
@@ -60,6 +60,9 @@ class Base(BaseSettings):
|
|
|
60
60
|
brave_search_api_key: str | None = None
|
|
61
61
|
brave_search_api_endpoint: str | None = None
|
|
62
62
|
|
|
63
|
+
# Perplexity API settings
|
|
64
|
+
perplexity_api_key: str | None = None
|
|
65
|
+
|
|
63
66
|
# VertexAI API settings
|
|
64
67
|
vertexai_service_account_credentials: str | None = None
|
|
65
68
|
vertexai_service_account_scopes: list[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
|
{unique_web_search-2026.24.0.dev2 → unique_web_search-2026.24.0.dev3}/src/unique_web_search/utils.py
RENAMED
|
File without changes
|