|
@@ -197,9 +197,78 @@ def bound_candidate_tools(
|
|
|
return tuple(output)
|
|
return tuple(output)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def _search_has_results(payload: dict[str, Any]) -> bool:
|
|
|
|
|
+ return bool(payload.get("search_results"))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+async def _search_provider_pages(
|
|
|
|
|
+ *,
|
|
|
|
|
+ service: Any,
|
|
|
|
|
+ run_id: str,
|
|
|
|
|
+ round_index: int,
|
|
|
|
|
+ keyword: str,
|
|
|
|
|
+ query_reason: str,
|
|
|
|
|
+ source_type: str,
|
|
|
|
|
+ provider: str,
|
|
|
|
|
+ raw_task: dict[str, Any],
|
|
|
|
|
+ common: dict[str, Any],
|
|
|
|
|
+ max_pages: int,
|
|
|
|
|
+ cursor: str | int,
|
|
|
|
|
+ provider_search_id: str = "",
|
|
|
|
|
+ backtrace: str = "",
|
|
|
|
|
+ extra_output: dict[str, Any] | None = None,
|
|
|
|
|
+) -> tuple[list[dict[str, Any]], bool]:
|
|
|
|
|
+ outputs: list[dict[str, Any]] = []
|
|
|
|
|
+ has_results = False
|
|
|
|
|
+ for page_no in range(1, max_pages + 1):
|
|
|
|
|
+ if provider == "tikhub":
|
|
|
|
|
+ payload = await search_tikhub(
|
|
|
|
|
+ **common,
|
|
|
|
|
+ cursor=int(cursor or 0),
|
|
|
|
|
+ filter_duration=str(raw_task.get("filter_duration") or "不限"),
|
|
|
|
|
+ search_id=provider_search_id,
|
|
|
|
|
+ backtrace=backtrace,
|
|
|
|
|
+ )
|
|
|
|
|
+ else:
|
|
|
|
|
+ payload = await search_internal(**common, cursor=str(cursor or "0"))
|
|
|
|
|
+ saved = service.save_search(
|
|
|
|
|
+ run_id=run_id,
|
|
|
|
|
+ round_index=int(round_index),
|
|
|
|
|
+ keyword=keyword,
|
|
|
|
|
+ query_reason=query_reason,
|
|
|
|
|
+ source_type=source_type,
|
|
|
|
|
+ provider=provider,
|
|
|
|
|
+ cursor=str(cursor),
|
|
|
|
|
+ page_no=page_no,
|
|
|
|
|
+ payload=payload,
|
|
|
|
|
+ )
|
|
|
|
|
+ if _search_has_results(payload):
|
|
|
|
|
+ has_results = True
|
|
|
|
|
+ outputs.append({
|
|
|
|
|
+ "keyword": keyword,
|
|
|
|
|
+ "provider": provider,
|
|
|
|
|
+ "page_no": page_no,
|
|
|
|
|
+ "error": payload.get("error"),
|
|
|
|
|
+ "has_more": bool(payload.get("has_more")),
|
|
|
|
|
+ "next_cursor": payload.get("next_cursor"),
|
|
|
|
|
+ **(extra_output or {}),
|
|
|
|
|
+ **saved,
|
|
|
|
|
+ })
|
|
|
|
|
+ if payload.get("error") or not payload.get("has_more"):
|
|
|
|
|
+ break
|
|
|
|
|
+ cursor = payload.get("next_cursor") or cursor
|
|
|
|
|
+ provider_search_id = str(payload.get("search_id") or provider_search_id)
|
|
|
|
|
+ backtrace = str(payload.get("backtrace") or backtrace)
|
|
|
|
|
+ return outputs, has_results
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
@tool
|
|
@tool
|
|
|
async def search_videos_v2(run_id: str, round_index: int, searches: list[dict[str, Any]]) -> str:
|
|
async def search_videos_v2(run_id: str, round_index: int, searches: list[dict[str, Any]]) -> str:
|
|
|
- """批量搜索并仅写入 find_agent_v2_search/candidate;searches 最多 6 项。"""
|
|
|
|
|
|
|
+ """批量搜索并仅写入 find_agent_v2_search/candidate;searches 最多 6 项。
|
|
|
|
|
+
|
|
|
|
|
+ 未指定 provider 时先打内部搜索,无候选再回退 TikHub。
|
|
|
|
|
+ 显式指定 internal_keyword 只用内部搜索;显式指定 tikhub 只用 TikHub。
|
|
|
|
|
+ """
|
|
|
if not searches or len(searches) > 6:
|
|
if not searches or len(searches) > 6:
|
|
|
return json.dumps({"error": "searches 必须为 1~6 项"}, ensure_ascii=False)
|
|
return json.dumps({"error": "searches 必须为 1~6 项"}, ensure_ascii=False)
|
|
|
service = get_find_agent_v2_service()
|
|
service = get_find_agent_v2_service()
|
|
@@ -207,58 +276,53 @@ async def search_videos_v2(run_id: str, round_index: int, searches: list[dict[st
|
|
|
for raw_task in searches:
|
|
for raw_task in searches:
|
|
|
keyword = str(raw_task.get("keyword") or "").strip()
|
|
keyword = str(raw_task.get("keyword") or "").strip()
|
|
|
reason = str(raw_task.get("query_reason") or "").strip()
|
|
reason = str(raw_task.get("query_reason") or "").strip()
|
|
|
- provider = str(raw_task.get("provider") or "internal_keyword")
|
|
|
|
|
|
|
+ requested_provider = str(raw_task.get("provider") or "").strip()
|
|
|
|
|
+ allow_tikhub_fallback = not requested_provider
|
|
|
|
|
+ provider = "tikhub" if requested_provider == "tikhub" else "internal_keyword"
|
|
|
if not keyword or not reason:
|
|
if not keyword or not reason:
|
|
|
outputs.append({"error": "keyword/query_reason 不能为空"})
|
|
outputs.append({"error": "keyword/query_reason 不能为空"})
|
|
|
continue
|
|
continue
|
|
|
max_pages = max(1, min(int(raw_task.get("max_pages") or 1), 2))
|
|
max_pages = max(1, min(int(raw_task.get("max_pages") or 1), 2))
|
|
|
- cursor: str | int = raw_task.get("cursor") or 0
|
|
|
|
|
- provider_search_id = str(raw_task.get("search_id") or "")
|
|
|
|
|
- backtrace = str(raw_task.get("backtrace") or "")
|
|
|
|
|
- for page_no in range(1, max_pages + 1):
|
|
|
|
|
- common = {
|
|
|
|
|
- "keyword": keyword,
|
|
|
|
|
- "content_type": str(raw_task.get("content_type") or "视频"),
|
|
|
|
|
- "sort_type": str(raw_task.get("sort_type") or "综合排序"),
|
|
|
|
|
- "publish_time": str(raw_task.get("publish_time") or "不限"),
|
|
|
|
|
- "min_duration_seconds": int(raw_task.get("min_duration_seconds") or 30),
|
|
|
|
|
- }
|
|
|
|
|
- if provider == "tikhub":
|
|
|
|
|
- payload = await search_tikhub(
|
|
|
|
|
- **common,
|
|
|
|
|
- cursor=int(cursor or 0),
|
|
|
|
|
- filter_duration=str(raw_task.get("filter_duration") or "不限"),
|
|
|
|
|
- search_id=provider_search_id,
|
|
|
|
|
- backtrace=backtrace,
|
|
|
|
|
- )
|
|
|
|
|
- else:
|
|
|
|
|
- provider = "internal_keyword"
|
|
|
|
|
- payload = await search_internal(**common, cursor=str(cursor or "0"))
|
|
|
|
|
- saved = service.save_search(
|
|
|
|
|
|
|
+ source_type = str(raw_task.get("source_type") or "mixed")
|
|
|
|
|
+ common = {
|
|
|
|
|
+ "keyword": keyword,
|
|
|
|
|
+ "content_type": str(raw_task.get("content_type") or "视频"),
|
|
|
|
|
+ "sort_type": str(raw_task.get("sort_type") or "综合排序"),
|
|
|
|
|
+ "publish_time": str(raw_task.get("publish_time") or "不限"),
|
|
|
|
|
+ "min_duration_seconds": int(raw_task.get("min_duration_seconds") or 30),
|
|
|
|
|
+ }
|
|
|
|
|
+ pages, has_results = await _search_provider_pages(
|
|
|
|
|
+ service=service,
|
|
|
|
|
+ run_id=run_id,
|
|
|
|
|
+ round_index=round_index,
|
|
|
|
|
+ keyword=keyword,
|
|
|
|
|
+ query_reason=reason,
|
|
|
|
|
+ source_type=source_type,
|
|
|
|
|
+ provider=provider,
|
|
|
|
|
+ raw_task=raw_task,
|
|
|
|
|
+ common=common,
|
|
|
|
|
+ max_pages=max_pages,
|
|
|
|
|
+ cursor=raw_task.get("cursor") or 0,
|
|
|
|
|
+ provider_search_id=str(raw_task.get("search_id") or ""),
|
|
|
|
|
+ backtrace=str(raw_task.get("backtrace") or ""),
|
|
|
|
|
+ )
|
|
|
|
|
+ outputs.extend(pages)
|
|
|
|
|
+ if allow_tikhub_fallback and not has_results:
|
|
|
|
|
+ fallback, _ = await _search_provider_pages(
|
|
|
|
|
+ service=service,
|
|
|
run_id=run_id,
|
|
run_id=run_id,
|
|
|
- round_index=int(round_index),
|
|
|
|
|
|
|
+ round_index=round_index,
|
|
|
keyword=keyword,
|
|
keyword=keyword,
|
|
|
query_reason=reason,
|
|
query_reason=reason,
|
|
|
- source_type=str(raw_task.get("source_type") or "mixed"),
|
|
|
|
|
- provider=provider,
|
|
|
|
|
- cursor=str(cursor),
|
|
|
|
|
- page_no=page_no,
|
|
|
|
|
- payload=payload,
|
|
|
|
|
|
|
+ source_type=source_type,
|
|
|
|
|
+ provider="tikhub",
|
|
|
|
|
+ raw_task=raw_task,
|
|
|
|
|
+ common=common,
|
|
|
|
|
+ max_pages=max_pages,
|
|
|
|
|
+ cursor=0,
|
|
|
|
|
+ extra_output={"fallback_from": "internal_keyword"},
|
|
|
)
|
|
)
|
|
|
- outputs.append({
|
|
|
|
|
- "keyword": keyword,
|
|
|
|
|
- "provider": provider,
|
|
|
|
|
- "page_no": page_no,
|
|
|
|
|
- "error": payload.get("error"),
|
|
|
|
|
- "has_more": bool(payload.get("has_more")),
|
|
|
|
|
- "next_cursor": payload.get("next_cursor"),
|
|
|
|
|
- **saved,
|
|
|
|
|
- })
|
|
|
|
|
- if payload.get("error") or not payload.get("has_more"):
|
|
|
|
|
- break
|
|
|
|
|
- cursor = payload.get("next_cursor") or cursor
|
|
|
|
|
- provider_search_id = str(payload.get("search_id") or provider_search_id)
|
|
|
|
|
- backtrace = str(payload.get("backtrace") or backtrace)
|
|
|
|
|
|
|
+ outputs.extend(fallback)
|
|
|
return json.dumps({"run_id": run_id, "searches": outputs}, ensure_ascii=False)
|
|
return json.dumps({"run_id": run_id, "searches": outputs}, ensure_ascii=False)
|
|
|
|
|
|
|
|
|
|
|