feat: add include_domains search filter and UI display
This commit is contained in:
parent
877bcc2fad
commit
c067df4e1b
@ -1647,6 +1647,13 @@ class MainTerminal:
|
||||
"country": {
|
||||
"type": "string",
|
||||
"description": "国家过滤,仅 topic=general 可用,使用英文小写国名"
|
||||
},
|
||||
"include_domains": {
|
||||
"type": "array",
|
||||
"description": "仅包含这些域名(可选,最多300个)",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}),
|
||||
"required": ["query"]
|
||||
@ -2209,7 +2216,8 @@ class MainTerminal:
|
||||
days=arguments.get("days"),
|
||||
start_date=arguments.get("start_date"),
|
||||
end_date=arguments.get("end_date"),
|
||||
country=arguments.get("country")
|
||||
country=arguments.get("country"),
|
||||
include_domains=arguments.get("include_domains")
|
||||
)
|
||||
|
||||
if search_response["success"]:
|
||||
|
||||
@ -424,6 +424,9 @@ class WebTerminal(MainTerminal):
|
||||
filters.append(f"{arguments.get('start_date')}~{arguments.get('end_date')}")
|
||||
if arguments.get("country"):
|
||||
filters.append(f"country={arguments.get('country')}")
|
||||
include_domains = arguments.get("include_domains")
|
||||
if isinstance(include_domains, list) and include_domains:
|
||||
filters.append(f"include_domains={len(include_domains)}")
|
||||
filter_text = " | ".join(filter_item for filter_item in filters if filter_item)
|
||||
self.broadcast('tool_status', {
|
||||
'tool': tool_name,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import httpx
|
||||
import json
|
||||
from typing import Dict, Optional, Any
|
||||
from typing import Dict, Optional, Any, List
|
||||
from datetime import datetime
|
||||
import re
|
||||
try:
|
||||
@ -42,7 +42,8 @@ class SearchEngine:
|
||||
days: Optional[int] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
country: Optional[str] = None
|
||||
country: Optional[str] = None,
|
||||
include_domains: Optional[List[str]] = None
|
||||
) -> Dict:
|
||||
"""
|
||||
执行网络搜索
|
||||
@ -56,6 +57,7 @@ class SearchEngine:
|
||||
start_date: 起始日期,格式YYYY-MM-DD
|
||||
end_date: 结束日期,格式YYYY-MM-DD
|
||||
country: 国家过滤,仅topic=general可用
|
||||
include_domains: 仅包含这些域名(最多300个)
|
||||
|
||||
Returns:
|
||||
搜索结果字典
|
||||
@ -75,7 +77,8 @@ class SearchEngine:
|
||||
days=days,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
country=country
|
||||
country=country,
|
||||
include_domains=include_domains
|
||||
)
|
||||
|
||||
if not validation["success"]:
|
||||
@ -165,7 +168,8 @@ class SearchEngine:
|
||||
days: Optional[int] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
country: Optional[str] = None
|
||||
country: Optional[str] = None,
|
||||
include_domains: Optional[List[str]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
搜索并返回格式化的摘要
|
||||
@ -185,7 +189,8 @@ class SearchEngine:
|
||||
days=days,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
country=country
|
||||
country=country,
|
||||
include_domains=include_domains
|
||||
)
|
||||
|
||||
if not results["success"]:
|
||||
@ -326,7 +331,8 @@ class SearchEngine:
|
||||
days: Optional[int],
|
||||
start_date: Optional[str],
|
||||
end_date: Optional[str],
|
||||
country: Optional[str]
|
||||
country: Optional[str],
|
||||
include_domains: Optional[List[str]]
|
||||
) -> Dict[str, Any]:
|
||||
"""验证并构建 Tavily 请求参数"""
|
||||
payload: Dict[str, Any] = {
|
||||
@ -458,6 +464,35 @@ class SearchEngine:
|
||||
}
|
||||
payload["country"] = normalized_country
|
||||
filters["country"] = normalized_country
|
||||
|
||||
# 域名白名单
|
||||
if include_domains is not None:
|
||||
if not isinstance(include_domains, list):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "include_domains 必须是字符串数组",
|
||||
"results": []
|
||||
}
|
||||
cleaned_domains = []
|
||||
for item in include_domains:
|
||||
if not isinstance(item, str):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "include_domains 中每一项都必须是字符串",
|
||||
"results": []
|
||||
}
|
||||
domain = item.strip().lower()
|
||||
if domain:
|
||||
cleaned_domains.append(domain)
|
||||
if len(cleaned_domains) > 300:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"include_domains 最多支持300个域名,当前: {len(cleaned_domains)}",
|
||||
"results": []
|
||||
}
|
||||
if cleaned_domains:
|
||||
payload["include_domains"] = cleaned_domains
|
||||
filters["include_domains"] = cleaned_domains
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
@ -485,6 +520,8 @@ class SearchEngine:
|
||||
|
||||
if "country" in filters:
|
||||
parts.append(f"Country: {filters['country']}")
|
||||
if "include_domains" in filters:
|
||||
parts.append(f"Domains: {len(filters['include_domains'])}")
|
||||
|
||||
if not parts:
|
||||
return ""
|
||||
|
||||
@ -196,6 +196,7 @@
|
||||
:get-tool-description="getToolDescription"
|
||||
:format-search-topic="formatSearchTopic"
|
||||
:format-search-time="formatSearchTime"
|
||||
:format-search-domains="formatSearchDomains"
|
||||
/>
|
||||
<VirtualMonitorSurface v-show="chatDisplayMode === 'monitor'" />
|
||||
|
||||
|
||||
@ -55,6 +55,7 @@ import {
|
||||
buildToolLabel,
|
||||
formatSearchTopic,
|
||||
formatSearchTime,
|
||||
formatSearchDomains,
|
||||
getLanguageClass
|
||||
} from './utils/chatDisplay';
|
||||
import {
|
||||
@ -4012,6 +4013,7 @@ const appOptions = {
|
||||
buildToolLabel,
|
||||
formatSearchTopic,
|
||||
formatSearchTime,
|
||||
formatSearchDomains,
|
||||
getLanguageClass,
|
||||
|
||||
scrollToBottom() {
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
:get-tool-description="getToolDescription"
|
||||
:format-search-topic="formatSearchTopic"
|
||||
:format-search-time="formatSearchTime"
|
||||
:format-search-domains="formatSearchDomains"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
@ -183,9 +184,10 @@
|
||||
:get-tool-animation-class="getToolAnimationClass"
|
||||
:get-tool-icon="getToolIcon"
|
||||
:get-tool-status-text="getToolStatusText"
|
||||
:get-tool-description="getToolDescription"
|
||||
:get-tool-description="getToolDescription"
|
||||
:format-search-topic="formatSearchTopic"
|
||||
:format-search-time="formatSearchTime"
|
||||
:format-search-domains="formatSearchDomains"
|
||||
:streaming-message="streamingMessage"
|
||||
:register-collapse-content="registerCollapseContent"
|
||||
:collapse-key="group.action.blockId || `${index}-tool-${group.actionIndex}`"
|
||||
@ -320,6 +322,7 @@
|
||||
:get-tool-description="getToolDescription"
|
||||
:format-search-topic="formatSearchTopic"
|
||||
:format-search-time="formatSearchTime"
|
||||
:format-search-domains="formatSearchDomains"
|
||||
:streaming-message="streamingMessage"
|
||||
:register-collapse-content="registerCollapseContent"
|
||||
:collapse-key="action.blockId || `${index}-tool-${actionIndex}`"
|
||||
@ -372,6 +375,7 @@ const props = defineProps<{
|
||||
getToolDescription: (tool: any) => string;
|
||||
formatSearchTopic: (filters: Record<string, any>) => string;
|
||||
formatSearchTime: (filters: Record<string, any>) => string;
|
||||
formatSearchDomains: (filters: Record<string, any>) => string;
|
||||
}>();
|
||||
|
||||
const personalization = usePersonalizationStore();
|
||||
|
||||
@ -86,6 +86,7 @@
|
||||
<div><strong>搜索内容:</strong>{{ action.tool.result.query || action.tool.arguments?.query }}</div>
|
||||
<div><strong>主题:</strong>{{ formatSearchTopic(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>时间范围:</strong>{{ formatSearchTime(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>限定网站:</strong>{{ formatSearchDomains(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>结果数量:</strong>{{ action.tool.result.total_results }}</div>
|
||||
</div>
|
||||
<div v-if="action.tool.result.results && action.tool.result.results.length" class="search-result-list">
|
||||
@ -139,6 +140,7 @@ const props = defineProps<{
|
||||
getToolDescription: (tool: any) => string;
|
||||
formatSearchTopic: (filters: Record<string, any>) => string;
|
||||
formatSearchTime: (filters: Record<string, any>) => string;
|
||||
formatSearchDomains: (filters: Record<string, any>) => string;
|
||||
}>();
|
||||
|
||||
const VISIBLE_LIMIT = 6;
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
<div><strong>搜索内容:</strong>{{ action.tool.result.query || action.tool.arguments.query }}</div>
|
||||
<div><strong>主题:</strong>{{ formatSearchTopic(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>时间范围:</strong>{{ formatSearchTime(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>限定网站:</strong>{{ formatSearchDomains(action.tool.result.filters || {}) }}</div>
|
||||
<div><strong>结果数量:</strong>{{ action.tool.result.total_results }}</div>
|
||||
</div>
|
||||
<div v-if="action.tool.result.results && action.tool.result.results.length" class="search-result-list">
|
||||
@ -77,6 +78,7 @@ defineProps<{
|
||||
getToolDescription: (tool: any) => string;
|
||||
formatSearchTopic: (filters: Record<string, any>) => string;
|
||||
formatSearchTime: (filters: Record<string, any>) => string;
|
||||
formatSearchDomains: (filters: Record<string, any>) => string;
|
||||
streamingMessage: boolean;
|
||||
registerCollapseContent?: (key: string, el: Element | null) => void;
|
||||
collapseKey?: string;
|
||||
|
||||
@ -284,6 +284,17 @@ export function formatSearchTime(filters: ToolPayload): string {
|
||||
return '未限定时间';
|
||||
}
|
||||
|
||||
export function formatSearchDomains(filters: ToolPayload): string {
|
||||
const domains = filters?.include_domains;
|
||||
if (!Array.isArray(domains) || domains.length === 0) {
|
||||
return '未限定网站';
|
||||
}
|
||||
const normalized = domains
|
||||
.map(item => String(item || '').trim())
|
||||
.filter(Boolean);
|
||||
return normalized.length ? normalized.join(', ') : '未限定网站';
|
||||
}
|
||||
|
||||
export function getLanguageClass(path: string): string {
|
||||
if (!path) {
|
||||
return 'language-plain';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user