GEO Task Worker v2 免安装版 (含嵌入式 Python + 全部依赖)
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.
 
 
 
 
 

149 lines
5.9 KiB

import base64
import hashlib
import json
import re
import time
from urllib.parse import quote
class WenxinClient:
BASE_URL = "https://chat.baidu.com"
def __init__(self, cookies=None):
self._cookie_str = ""
if cookies:
self._cookie_str = "; ".join(f'{c["name"]}={c["value"]}' for c in cookies)
async def chat(self, question, thinking=False):
from curl_cffi.requests import AsyncSession
async with AsyncSession(impersonate="chrome136", verify=False) as session:
if self._cookie_str:
session.headers["cookie"] = self._cookie_str
resp = await session.get(self.BASE_URL + "/", timeout=20)
match = re.search(r'\{"token"\s*:\s*"([^"]+)"\s*,\s*"lid"\s*:\s*"(\d+)"', resp.text)
if not match:
return "", ""
token, lid = match.group(1), match.group(2)
ts = int(time.time() * 1000)
query_md5 = hashlib.md5(question.encode("utf-8")).hexdigest()
raw_token = f"{token}|{query_md5}|{ts}|{lid}"
chat_token = f"{base64.b64encode(raw_token.encode()).decode()}-{lid}-3"
payload = {
"message": {
"inputMethod": "chat_search", "isRebuild": False,
"content": {
"query": "", "qtype": 0,
"agentInfo": {"agent_id": [""], "params": json.dumps({"agt_rk": 1, "agt_sess_cnt": 1})},
"agentInfoList": [],
},
"searchInfo": {
"srcid": "", "order": "", "tplname": "", "dqaKey": "",
"re_rank": "1", "ori_lid": "", "sa": "bkb", "enter_type": "chat_url",
"chatParams": {"setype": "csaitab", "chat_samples": "WISE_NEW_CSAITAB",
"chat_token": chat_token, "scene": ""},
"isPrivateChat": False,
"usedModel": {
"modelName": "smartMode",
"modelFunction": {"deepSearch": "1" if thinking else "0", "thinkMode": "0"},
"showModelName": "smartMode",
},
"landingPageSwitch": "", "landingPage": "aitab", "isInnovate": 2,
"showMindMap": False,
},
"from": "", "source": "pc_csaitab",
"query": [{"type": "TEXT", "data": {"text": {"query": question, "extData": "{}", "text_type": ""}}}],
"anti_ext": {"inputT": None},
},
"sa": "bkb", "setype": "csaitab", "rank": 1,
}
headers = {
"Accept": "text/event-stream", "Content-Type": "application/json",
"Origin": self.BASE_URL, "Referer": f"{self.BASE_URL}/",
"source": "pc_csaitab", "isDeepseek": "1",
"X-Chat-Message": f"query:{quote(question)},anti_ext:%7B%22inputT%22%3Anull%7D,enter_type:chat_url,re_rank:1,modelName:smartMode,sa:bkb",
}
resp = await session.post(
self.BASE_URL + "/aichat/api/conversation",
headers=headers, json=payload, stream=True, timeout=180,
)
raw_text = ""
req_body = json.dumps(payload, ensure_ascii=False)
async for chunk in resp.aiter_content():
raw_text += chunk.decode("utf-8", errors="replace")
return raw_text, req_body
async def extract_wenxin_cookies():
from playwright.async_api import async_playwright
from .base import CDP_URL
try:
async with async_playwright() as pw:
browser = await pw.chromium.connect_over_cdp(CDP_URL)
ctx = browser.contexts[0]
cookies = await ctx.cookies(["https://chat.baidu.com", "https://www.baidu.com", "https://baidu.com"])
if any(c["name"] in ("BDUSS", "BDUSS_BFESS") for c in cookies):
return cookies
except Exception:
pass
return None
async def get_wenxin_share_url(lid, wx_page=None):
from playwright.async_api import async_playwright
from .base import CDP_URL
page = wx_page
pw_ctx = None
try:
if not page:
pw_ctx = await async_playwright().start()
browser = await pw_ctx.chromium.connect_over_cdp(CDP_URL)
page = next((p for p in browser.contexts[0].pages if "baidu.com" in p.url), None)
if not page:
if pw_ctx:
await pw_ctx.stop()
return ""
await page.goto(f"https://chat.baidu.com/search/{lid}", wait_until="domcontentloaded", timeout=20000)
await asyncio.sleep(3)
await page.evaluate("""() => {
window.__sc = [];
const of = window.fetch;
window.fetch = async function(...a) {
const r = await of.apply(this, a);
try { const c=r.clone(); const t=await c.text();
if (t.includes('short_url')) window.__sc.push(t);
} catch {}
return r;
};
}""")
await page.click(".cos-icon-share1", timeout=8000)
await asyncio.sleep(1)
await page.click('button:has-text("复制链接")', timeout=5000)
await asyncio.sleep(2)
captures = await page.evaluate("() => window.__sc")
import json as _json
for c in captures:
d = _json.loads(c)
url = d.get("data", {}).get("short_url", "")
if url:
if pw_ctx:
await pw_ctx.stop()
return url
if pw_ctx:
await pw_ctx.stop()
except Exception as e:
print(f" ⚠ 文心分享链接获取失败 (lid={lid}): {e}")
if pw_ctx:
try:
await pw_ctx.stop()
except Exception:
pass
return ""