You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
4.2 KiB
108 lines
4.2 KiB
import json
|
|
import re
|
|
from datetime import datetime, timezone, timedelta
|
|
from typing import Any
|
|
|
|
TZ_CN = timezone(timedelta(hours=8))
|
|
|
|
|
|
def _now_collect_time() -> str:
|
|
return datetime.now(TZ_CN).strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
def format_collected_at(value: Any = None) -> str:
|
|
if value is None or (isinstance(value, str) and not value.strip()):
|
|
return _now_collect_time()
|
|
if isinstance(value, datetime):
|
|
dt = value
|
|
if dt.tzinfo is not None:
|
|
dt = dt.astimezone(TZ_CN)
|
|
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
s = str(value).strip()
|
|
if re.fullmatch(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}", s):
|
|
return s
|
|
if re.fullmatch(r"\d{4}-\d{2}-\d{2}", s):
|
|
return f"{s} 00:00:00"
|
|
try:
|
|
dt = datetime.fromisoformat(s.replace("Z", "+00:00"))
|
|
if dt.tzinfo is not None:
|
|
dt = dt.astimezone(TZ_CN)
|
|
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
except Exception:
|
|
pass
|
|
m = re.match(r"^(\d{4})[/-](\d{1,2})[/-](\d{1,2})[ T](\d{1,2}):(\d{1,2})(?::(\d{1,2}))?", s)
|
|
if m:
|
|
y, mo, d, h, mi, sec = m.groups()
|
|
return f"{int(y):04d}-{int(mo):02d}-{int(d):02d} {int(h):02d}:{int(mi):02d}:{int(sec or 0):02d}"
|
|
print(f" [WARN] collectedAt 无法解析 {s!r}, 使用当前时间")
|
|
return _now_collect_time()
|
|
|
|
|
|
def build_submit_payload(task: dict, parsed: dict, location: str = "") -> dict:
|
|
result = parsed.get("result") or {}
|
|
sources = parsed.get("sources") or []
|
|
answer = (result.get("answer") or "").strip()
|
|
think = (result.get("thinking_process") or "").strip() or None
|
|
related = result.get("related_questions") or []
|
|
if isinstance(related, list):
|
|
extended = "\n".join(str(x) for x in related if x) or None
|
|
else:
|
|
extended = str(related) if related else None
|
|
|
|
search_links = []
|
|
for i, sr in enumerate(sources, 1):
|
|
url = sr.get("source_url") or ""
|
|
if not url:
|
|
continue
|
|
search_links.append({
|
|
"url": url, "index": i,
|
|
"title": sr.get("source_title") or "",
|
|
"source": sr.get("source_name") or "",
|
|
"snippet": sr.get("snippet") or sr.get("body") or None,
|
|
"site_name": sr.get("source_name") or "",
|
|
"site_icon": sr.get("source_icon") or "",
|
|
"published_time": sr.get("source_publish_date") or "",
|
|
})
|
|
|
|
adopted = [{"url": u, "title": ""} for u in (result.get("cited_links") or []) if u]
|
|
shared = []
|
|
share_link = result.get("share_link") or ""
|
|
if share_link:
|
|
shared.append({"url": share_link, "title": ""})
|
|
|
|
meta_infos = []
|
|
for img in (result.get("image_links") or []):
|
|
if img:
|
|
meta_infos.append({
|
|
"source_type": "image", "url": img, "title": "", "summary": "",
|
|
"website_name": "", "icon": "",
|
|
"value": json.dumps({"images": [{"full_size_url": [img]}], "videos": []}, ensure_ascii=False),
|
|
})
|
|
for vid in (result.get("video_links") or []):
|
|
if vid:
|
|
meta_infos.append({
|
|
"source_type": "video", "url": vid, "title": "", "summary": "",
|
|
"website_name": "", "icon": "",
|
|
"value": json.dumps({"images": [], "videos": [{"url": vid}]}, ensure_ascii=False),
|
|
})
|
|
|
|
deep = int(task.get("deepThinking") if task.get("deepThinking") is not None
|
|
else parsed.get("deep_thinking") or 0)
|
|
web = int(task.get("webSearch") if task.get("webSearch") is not None
|
|
else (1 if parsed.get("is_online") else 0))
|
|
task_id = str(task.get("id") or "").strip()
|
|
dispatch_id = str(task.get("dispatchId") or "").strip()
|
|
collected_at = format_collected_at(
|
|
parsed.get("collect_time") or (parsed.get("result") or {}).get("collect_time")
|
|
or task.get("collectedAt")
|
|
)
|
|
|
|
return {
|
|
"id": task_id, "dispatchId": dispatch_id, "collectedAt": collected_at,
|
|
"answer": answer, "thinkText": think,
|
|
"deepThinking": 1 if deep else 0, "webSearch": 1 if web else 0,
|
|
"model": task.get("model") or "", "location": location or "",
|
|
"extendedQuestion": extended, "searchLinks": search_links,
|
|
"adoptedLinks": adopted, "sharedLinks": shared,
|
|
"metaInfos": meta_infos, "productLinkList": [],
|
|
}
|