File size: 6,080 Bytes
6d60378 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | #!/usr/bin/env python3
"""WorkBuddy 活跃上报探针 / 解冻工具.
用途
probe 只读:查某账号 growth 任务状态 + streak
report 写:向 /v2/report 发一条 chat_request_send(点亮活跃/连登 + 解锁 first_buddy)
unlock 写:report -> agreement -> buddy/first(无猫号领免费猫)
用法
python3 probe_active.py probe 00e26541
python3 probe_active.py report 0225284f
python3 probe_active.py unlock 0225284f --yes
python3 probe_active.py report ALL --yes --gap 1.05 # 全池
注意
- 默认 dry-run:写动作必须显式加 --yes
- 单账号同接口间隔 >=1.05s(--gap)
- body 必须含 userId 字段,否则服务端 200 但静默丢弃
"""
import json, os, sys, time, glob, argparse, urllib.request, urllib.error
AUTHS = "/root/workbuddy2api/auths"
CHAT_BASE = "https://copilot.tencent.com" # growth / report
BILL_BASE = "https://www.codebuddy.cn" # billing / report
def cred(prefix):
hits = glob.glob(os.path.join(AUTHS, f"workbuddy-{prefix}*.json"))
if not hits:
raise SystemExit(f"no auth for {prefix}")
d = json.load(open(hits[0]))
a, acc = d["auth"], d["account"]
return {"token": a["accessToken"], "domain": a.get("domain") or "",
"uid": acc["uid"], "nick": acc.get("nickname", ""),
"file": os.path.basename(hits[0])}
def call(c, method, path, body=None, host=CHAT_BASE, timeout=30):
url = path if path.startswith("http") else host + path
hdr = {"Authorization": "Bearer " + c["token"], "X-User-Id": c["uid"],
"X-Domain": c["domain"], "Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "CLI/2.63.2 CodeBuddy/2.63.2",
"Origin": "https://www.codebuddy.cn", "Referer": "https://www.codebuddy.cn/"}
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(url, data=data, headers=hdr, method=method)
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.status, json.loads(r.read().decode("utf-8", "replace"))
except urllib.error.HTTPError as e:
t = e.read().decode("utf-8", "replace")
try: return e.code, json.loads(t)
except Exception: return e.code, {"raw": t[:300]}
except Exception as e:
return -1, {"err": repr(e)}
def chat_event(c, conversation_id=None):
"""客户端 chat_request_send 事件形状(照抄 CLI,勿删 userId)。"""
now = int(time.time() * 1000)
cid = conversation_id or f"wb-active-{now}"
return {"eventCode": "chat_request_send", "timestamp": now, "reportDelay": 0,
"mode": "craft", "conversationId": cid, "requestId": cid,
"inputLength": 12, "requestModelId": "deepseek-v4-flash",
"requestModelName": "DeepSeek V4 Flash", "isPlan": False,
"isAutoExecuteTerminal": False, "isAutoModify": False,
"codebaseEnable": False, "maxToken": 0, "maxSteps": 0, "temperature": 0,
"maxRetries": 0, "mentionContexts": [], "knowledgeId": [],
"knowledgeName": [], "codebaseId": "", "mentionContextCount": 0,
"command": "", "expertId": "", "recommendId": "", "skillId": "",
"skillCount": 0, "totalCount": 0, "fileUri": "", "presentAt": now,
"traceId": "", "rootRequestId": cid, "parentConversationId": cid,
"agentName": "default", "agentType": "conversation", "userId": c["uid"]}
def report_activity(c):
"""点亮活跃/连登。返回 (status, code)."""
st, r = call(c, "POST", "/v2/report", [chat_event(c)], host=BILL_BASE)
return st, r.get("code")
def tasks(c):
st, d = call(c, "GET", "/v2/activity/growth/tasks")
out = {}
for t in (d.get("data", {}).get("tasks") or []):
out[t["task_code"]] = (t["accept_status"], t.get("progress"))
return out
def unlock(c, n_reports=6):
"""无猫号解冻:report -> agreement -> buddy/first -> chat_5"""
st, code = report_activity(c)
print(f" report -> {st} code={code}")
time.sleep(2)
st, ag = call(c, "POST", "/activity/growth/buddy/agreement", {"agree": True})
print(f" agreement -> {st} code={ag.get('code')}")
st, bf = call(c, "POST", "/activity/growth/buddy/first", {})
d = bf.get("data") or {}
print(f" buddy/first -> {st} {bf.get('msg')} credit={d.get('credit')} energy={d.get('energy')}")
return bf
def main():
ap = argparse.ArgumentParser()
ap.add_argument("action", choices=["probe", "report", "unlock"])
ap.add_argument("account", help="uid 前缀,或 ALL")
ap.add_argument("--yes", action="store_true", help="确认执行写操作")
ap.add_argument("--gap", type=float, default=1.05)
a = ap.parse_args()
if a.account.upper() == "ALL":
prefixes = [os.path.basename(p)[10:18]
for p in sorted(glob.glob(AUTHS + "/workbuddy-*.json"))]
else:
prefixes = [a.account]
for pre in prefixes:
c = cred(pre)
print(f"== {c['uid'][:8]} ({c['nick']}) ==")
if a.action == "probe":
t = tasks(c)
st, s = call(c, "GET", "/activity/growth/streak")
print(" first_buddy:", t.get("first_buddy"),
"| RichMeow_Chat:", t.get("RichMeow_Chat"),
"| chat_5:", t.get("chat_5"))
print(" streak.days:", (s.get("data", {}).get("streak", {}) or {}).get("days"))
elif a.action == "report":
if not a.yes:
print(" [dry-run] 将上报 1 条 chat_request_send(加 --yes 执行)")
else:
print(" report ->", report_activity(c))
else: # unlock
if not a.yes:
print(" [dry-run] 将 report + agreement + buddy/first(加 --yes 执行)")
else:
unlock(c)
time.sleep(a.gap)
if __name__ == "__main__":
main()
|