mirror of
https://github.com/open-webui/open-webui
synced 2025-05-23 14:24:22 +00:00
Merge pull request #12683 from Youggls/dev
feat: Add sougou web search engine.
This commit is contained in:
commit
1865e29bfc
@ -2142,6 +2142,18 @@ PERPLEXITY_API_KEY = PersistentConfig(
|
|||||||
os.getenv("PERPLEXITY_API_KEY", ""),
|
os.getenv("PERPLEXITY_API_KEY", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SOUGOU_API_SID = PersistentConfig(
|
||||||
|
"SOUGOU_API_SID",
|
||||||
|
"rag.web.search.sougou_api_sid",
|
||||||
|
os.getenv("SOUGOU_API_SID", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
SOUGOU_API_SK = PersistentConfig(
|
||||||
|
"SOUGOU_API_SK",
|
||||||
|
"rag.web.search.sougou_api_sk",
|
||||||
|
os.getenv("SOUGOU_API_SK", ""),
|
||||||
|
)
|
||||||
|
|
||||||
RAG_WEB_SEARCH_RESULT_COUNT = PersistentConfig(
|
RAG_WEB_SEARCH_RESULT_COUNT = PersistentConfig(
|
||||||
"RAG_WEB_SEARCH_RESULT_COUNT",
|
"RAG_WEB_SEARCH_RESULT_COUNT",
|
||||||
"rag.web.search.result_count",
|
"rag.web.search.result_count",
|
||||||
|
@ -225,6 +225,8 @@ from open_webui.config import (
|
|||||||
BRAVE_SEARCH_API_KEY,
|
BRAVE_SEARCH_API_KEY,
|
||||||
EXA_API_KEY,
|
EXA_API_KEY,
|
||||||
PERPLEXITY_API_KEY,
|
PERPLEXITY_API_KEY,
|
||||||
|
SOUGOU_API_SID,
|
||||||
|
SOUGOU_API_SK,
|
||||||
KAGI_SEARCH_API_KEY,
|
KAGI_SEARCH_API_KEY,
|
||||||
MOJEEK_SEARCH_API_KEY,
|
MOJEEK_SEARCH_API_KEY,
|
||||||
BOCHA_SEARCH_API_KEY,
|
BOCHA_SEARCH_API_KEY,
|
||||||
@ -652,6 +654,8 @@ app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT
|
|||||||
app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY
|
app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY
|
||||||
app.state.config.EXA_API_KEY = EXA_API_KEY
|
app.state.config.EXA_API_KEY = EXA_API_KEY
|
||||||
app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY
|
app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY
|
||||||
|
app.state.config.SOUGOU_API_SID = SOUGOU_API_SID
|
||||||
|
app.state.config.SOUGOU_API_SK = SOUGOU_API_SK
|
||||||
|
|
||||||
app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = RAG_WEB_SEARCH_RESULT_COUNT
|
app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = RAG_WEB_SEARCH_RESULT_COUNT
|
||||||
app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = RAG_WEB_SEARCH_CONCURRENT_REQUESTS
|
app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = RAG_WEB_SEARCH_CONCURRENT_REQUESTS
|
||||||
|
48
backend/open_webui/retrieval/web/sougou.py
Normal file
48
backend/open_webui/retrieval/web/sougou.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import logging
|
||||||
|
import json
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
from tencentcloud.common.common_client import CommonClient
|
||||||
|
from tencentcloud.common import credential
|
||||||
|
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
|
||||||
|
from tencentcloud.common.profile.client_profile import ClientProfile
|
||||||
|
from tencentcloud.common.profile.http_profile import HttpProfile
|
||||||
|
|
||||||
|
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
|
||||||
|
from open_webui.env import SRC_LOG_LEVELS
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
||||||
|
|
||||||
|
|
||||||
|
def search_sougou(
|
||||||
|
sougou_api_sid: str,
|
||||||
|
sougou_api_sk: str,
|
||||||
|
query: str,
|
||||||
|
count: int,
|
||||||
|
filter_list: Optional[List[str]] = None,
|
||||||
|
) -> List[SearchResult]:
|
||||||
|
try:
|
||||||
|
cred = credential.Credential(sougou_api_sid, sougou_api_sk)
|
||||||
|
http_profile = HttpProfile()
|
||||||
|
http_profile.endpoint = "tms.tencentcloudapi.com"
|
||||||
|
client_profile = ClientProfile()
|
||||||
|
client_profile.http_profile = http_profile
|
||||||
|
params = json.dumps({"Query": query, 'Cnt': 20})
|
||||||
|
common_client = CommonClient("tms", "2020-12-29", cred, "", profile=client_profile)
|
||||||
|
results = [
|
||||||
|
json.loads(page) for page in common_client.call_json("SearchPro", json.loads(params))["Response"]["Pages"]
|
||||||
|
]
|
||||||
|
sorted_results = sorted(results, key=lambda x: x.get("scour", 0.0), reverse=True)
|
||||||
|
if filter_list:
|
||||||
|
sorted_results = get_filtered_results(sorted_results, filter_list)
|
||||||
|
|
||||||
|
return [
|
||||||
|
SearchResult(
|
||||||
|
link=result.get("url"), title=result.get("title"), snippet=result.get("passage")
|
||||||
|
)
|
||||||
|
for result in sorted_results[:count]
|
||||||
|
]
|
||||||
|
except TencentCloudSDKException as err:
|
||||||
|
log.error(f"Error in Sougou search: {err}")
|
||||||
|
return []
|
@ -60,6 +60,7 @@ from open_webui.retrieval.web.tavily import search_tavily
|
|||||||
from open_webui.retrieval.web.bing import search_bing
|
from open_webui.retrieval.web.bing import search_bing
|
||||||
from open_webui.retrieval.web.exa import search_exa
|
from open_webui.retrieval.web.exa import search_exa
|
||||||
from open_webui.retrieval.web.perplexity import search_perplexity
|
from open_webui.retrieval.web.perplexity import search_perplexity
|
||||||
|
from open_webui.retrieval.web.sougou import search_sougou
|
||||||
|
|
||||||
from open_webui.retrieval.utils import (
|
from open_webui.retrieval.utils import (
|
||||||
get_embedding_function,
|
get_embedding_function,
|
||||||
@ -411,6 +412,8 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
|
|||||||
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
|
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
|
||||||
"exa_api_key": request.app.state.config.EXA_API_KEY,
|
"exa_api_key": request.app.state.config.EXA_API_KEY,
|
||||||
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
|
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
|
||||||
|
"sougou_api_sid": request.app.state.config.SOUGOU_API_SID,
|
||||||
|
"sougou_api_sk": request.app.state.config.SOUGOU_API_SK,
|
||||||
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
||||||
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
|
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
|
||||||
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
|
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
|
||||||
@ -478,6 +481,8 @@ class WebSearchConfig(BaseModel):
|
|||||||
bing_search_v7_subscription_key: Optional[str] = None
|
bing_search_v7_subscription_key: Optional[str] = None
|
||||||
exa_api_key: Optional[str] = None
|
exa_api_key: Optional[str] = None
|
||||||
perplexity_api_key: Optional[str] = None
|
perplexity_api_key: Optional[str] = None
|
||||||
|
sougou_api_sid: Optional[str] = None
|
||||||
|
sougou_api_sk: Optional[str] = None
|
||||||
result_count: Optional[int] = None
|
result_count: Optional[int] = None
|
||||||
concurrent_requests: Optional[int] = None
|
concurrent_requests: Optional[int] = None
|
||||||
trust_env: Optional[bool] = None
|
trust_env: Optional[bool] = None
|
||||||
@ -640,6 +645,12 @@ async def update_rag_config(
|
|||||||
request.app.state.config.PERPLEXITY_API_KEY = (
|
request.app.state.config.PERPLEXITY_API_KEY = (
|
||||||
form_data.web.search.perplexity_api_key
|
form_data.web.search.perplexity_api_key
|
||||||
)
|
)
|
||||||
|
request.app.state.config.SOUGOU_API_SID = (
|
||||||
|
form_data.web.search.sougou_api_sid
|
||||||
|
)
|
||||||
|
request.app.state.config.SOUGOU_API_SK = (
|
||||||
|
form_data.web.search.sougou_api_sk
|
||||||
|
)
|
||||||
|
|
||||||
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = (
|
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = (
|
||||||
form_data.web.search.result_count
|
form_data.web.search.result_count
|
||||||
@ -712,6 +723,8 @@ async def update_rag_config(
|
|||||||
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
|
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
|
||||||
"exa_api_key": request.app.state.config.EXA_API_KEY,
|
"exa_api_key": request.app.state.config.EXA_API_KEY,
|
||||||
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
|
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
|
||||||
|
"sougou_api_sid": request.app.state.config.SOUGOU_API_SID,
|
||||||
|
"sougou_api_sk": request.app.state.config.SOUGOU_API_SK,
|
||||||
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
||||||
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
|
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
|
||||||
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
|
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
|
||||||
@ -1267,6 +1280,7 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
|
|||||||
- TAVILY_API_KEY
|
- TAVILY_API_KEY
|
||||||
- EXA_API_KEY
|
- EXA_API_KEY
|
||||||
- PERPLEXITY_API_KEY
|
- PERPLEXITY_API_KEY
|
||||||
|
- SOUGOU_API_SID + SOUGOU_API_SK
|
||||||
- SEARCHAPI_API_KEY + SEARCHAPI_ENGINE (by default `google`)
|
- SEARCHAPI_API_KEY + SEARCHAPI_ENGINE (by default `google`)
|
||||||
- SERPAPI_API_KEY + SERPAPI_ENGINE (by default `google`)
|
- SERPAPI_API_KEY + SERPAPI_ENGINE (by default `google`)
|
||||||
Args:
|
Args:
|
||||||
@ -1438,6 +1452,17 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
|
|||||||
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
||||||
request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
|
request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
|
||||||
)
|
)
|
||||||
|
elif engine == 'sougou':
|
||||||
|
if request.app.state.config.SOUGOU_API_SID and request.app.state.config.SOUGOU_API_SK:
|
||||||
|
return search_sougou(
|
||||||
|
request.app.state.config.SOUGOU_API_SID,
|
||||||
|
request.app.state.config.SOUGOU_API_SK,
|
||||||
|
query,
|
||||||
|
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
||||||
|
request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise Exception("No SOUGOU_API_SID or SOUGOU_API_SK found in environment variables")
|
||||||
else:
|
else:
|
||||||
raise Exception("No search engine API key found in environment variables")
|
raise Exception("No search engine API key found in environment variables")
|
||||||
|
|
||||||
|
@ -123,6 +123,9 @@ ldap3==2.9.1
|
|||||||
## Firecrawl
|
## Firecrawl
|
||||||
firecrawl-py==1.12.0
|
firecrawl-py==1.12.0
|
||||||
|
|
||||||
|
# Sougou API SDK(Tencentcloud SDK)
|
||||||
|
tencentcloud-sdk-python==3.0.1336
|
||||||
|
|
||||||
## Trace
|
## Trace
|
||||||
opentelemetry-api==1.31.1
|
opentelemetry-api==1.31.1
|
||||||
opentelemetry-sdk==1.31.1
|
opentelemetry-sdk==1.31.1
|
||||||
|
@ -125,6 +125,8 @@ dependencies = [
|
|||||||
|
|
||||||
"firecrawl-py==1.12.0",
|
"firecrawl-py==1.12.0",
|
||||||
|
|
||||||
|
"tencentcloud-sdk-python==3.0.1336",
|
||||||
|
|
||||||
"gcp-storage-emulator>=2024.8.3",
|
"gcp-storage-emulator>=2024.8.3",
|
||||||
]
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
'jina',
|
'jina',
|
||||||
'bing',
|
'bing',
|
||||||
'exa',
|
'exa',
|
||||||
'perplexity'
|
'perplexity',
|
||||||
|
'sougou'
|
||||||
];
|
];
|
||||||
|
|
||||||
let youtubeLanguage = 'en';
|
let youtubeLanguage = 'en';
|
||||||
@ -404,6 +405,31 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{:else if webConfig.search.engine === 'sougou'}
|
||||||
|
<div class="mb-2.5 flex w-full flex-col">
|
||||||
|
<div>
|
||||||
|
<div class=" self-center text-xs font-medium mb-1">
|
||||||
|
{$i18n.t('Sougou Search API sID')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SensitiveInput
|
||||||
|
placeholder={$i18n.t('Enter Sougou Search API sID')}
|
||||||
|
bind:value={webConfig.search.sougou_api_sid}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2.5 flex w-full flex-col">
|
||||||
|
<div>
|
||||||
|
<div class=" self-center text-xs font-medium mb-1">
|
||||||
|
{$i18n.t('Sougou Search API SK')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SensitiveInput
|
||||||
|
placeholder={$i18n.t('Enter Sougou Search API SK')}
|
||||||
|
bind:value={webConfig.search.sougou_api_sk}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -424,6 +424,8 @@
|
|||||||
"Enter Mojeek Search API Key": "",
|
"Enter Mojeek Search API Key": "",
|
||||||
"Enter Number of Steps (e.g. 50)": "",
|
"Enter Number of Steps (e.g. 50)": "",
|
||||||
"Enter Perplexity API Key": "",
|
"Enter Perplexity API Key": "",
|
||||||
|
"Enter Sougou Search API sID": "",
|
||||||
|
"Enter Sougou Search API SK": "",
|
||||||
"Enter proxy URL (e.g. https://user:password@host:port)": "",
|
"Enter proxy URL (e.g. https://user:password@host:port)": "",
|
||||||
"Enter reasoning effort": "",
|
"Enter reasoning effort": "",
|
||||||
"Enter Sampler (e.g. Euler a)": "",
|
"Enter Sampler (e.g. Euler a)": "",
|
||||||
@ -822,6 +824,8 @@
|
|||||||
"Permission denied when accessing microphone: {{error}}": "",
|
"Permission denied when accessing microphone: {{error}}": "",
|
||||||
"Permissions": "",
|
"Permissions": "",
|
||||||
"Perplexity API Key": "",
|
"Perplexity API Key": "",
|
||||||
|
"Sougou Search API sID": "",
|
||||||
|
"Sougou Search API SK": "",
|
||||||
"Personalization": "",
|
"Personalization": "",
|
||||||
"Pin": "",
|
"Pin": "",
|
||||||
"Pinned": "",
|
"Pinned": "",
|
||||||
|
@ -424,6 +424,8 @@
|
|||||||
"Enter Mojeek Search API Key": "输入 Mojeek Search API 密钥",
|
"Enter Mojeek Search API Key": "输入 Mojeek Search API 密钥",
|
||||||
"Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps) (例如:50)",
|
"Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps) (例如:50)",
|
||||||
"Enter Perplexity API Key": "输入 Perplexity API 密钥",
|
"Enter Perplexity API Key": "输入 Perplexity API 密钥",
|
||||||
|
"Enter Sougou Search API sID": "输入搜狗搜索 API 的 Secret ID",
|
||||||
|
"Enter Sougou Search API SK": "输入搜狗搜索 API 的 Secret Key",
|
||||||
"Enter proxy URL (e.g. https://user:password@host:port)": "输入代理 URL (例如:https://用户名:密码@主机名:端口)",
|
"Enter proxy URL (e.g. https://user:password@host:port)": "输入代理 URL (例如:https://用户名:密码@主机名:端口)",
|
||||||
"Enter reasoning effort": "设置推理努力",
|
"Enter reasoning effort": "设置推理努力",
|
||||||
"Enter Sampler (e.g. Euler a)": "输入 Sampler (例如:Euler a)",
|
"Enter Sampler (e.g. Euler a)": "输入 Sampler (例如:Euler a)",
|
||||||
@ -822,6 +824,8 @@
|
|||||||
"Permission denied when accessing microphone: {{error}}": "申请麦克风权限被拒绝:{{error}}",
|
"Permission denied when accessing microphone: {{error}}": "申请麦克风权限被拒绝:{{error}}",
|
||||||
"Permissions": "权限",
|
"Permissions": "权限",
|
||||||
"Perplexity API Key": "Perplexity API 密钥",
|
"Perplexity API Key": "Perplexity API 密钥",
|
||||||
|
"Sougou Search API sID": "搜狗搜索 API 的 Secret ID",
|
||||||
|
"Sougou Search API SK": "搜狗搜索 API 的 Secret Key",
|
||||||
"Personalization": "个性化",
|
"Personalization": "个性化",
|
||||||
"Pin": "置顶",
|
"Pin": "置顶",
|
||||||
"Pinned": "已置顶",
|
"Pinned": "已置顶",
|
||||||
|
Loading…
Reference in New Issue
Block a user