Files
daymade 94151b3572 chore: land restored working-tree work after PII history cleanup
All uncommitted work (stashed during the main-branch PII history rewrite, then
restored and verified clean by gitleaks + grep + a Layer-4 semantic read) lands here:

- financial: merge 5 finance skills (ashare-news-fetcher, bigdata-skill,
  financial-data-collector, gangtise-copilot, pharma-daily-report) into the
  daymade-financial suite
- skill-creator: methodology + SKILL.md upgrades (counter-review filtering,
  reproduce-in-isolation + disprove, script-robustness specifics, direction-first
  capture) + remove hardcoded personal identifiers from quick_validate's detector
- claude-switch-models-setup: per-profile known_marketplaces.json root-cause fix,
  self-contained sync script, review-driven hardening
- new skills: design-style-picker, local-codex, openclaw-model-switch,
  claude-migrate-memory-to-doc
- marketplace.json: register merged suite + version bumps
- misc: CLAUDE.md / README / CHANGELOG / transcript-fixer updates

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsT94yTJUNmR9prwyaz1FW
2026-06-29 01:43:57 +08:00

143 lines
5.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""bigdata_toolkit 可跑示例
============================
演示五大能力,全部小样本(成本意识),并用 CostTracker 量化每段消耗。
运行
----
::
export BIGDATA_API_KEY=bd_v2_xxx # 你的 Bigdata API key
export HTTPS_PROXY=http://127.0.0.1:8080 # 仅在需要出站代理时
# 用装好 bigdata-client 的 Python 环境跑(见 SKILL.md 装包步骤):
python scripts/probe_example.py # 加 --with-search 额外测 chunk 检索
设计原则
--------
- 实体解析 / events / estimates / quota 这些 endpoint **不按 chunk 计费**,
近乎零成本,所以默认演示它们。
- search(query-chunks)**按 chunk 计费**,示例用 ``chunk_limit=10``(≈1 qu),
并用 ``--with-search`` 显式开启,避免误烧配额。
"""
from __future__ import annotations
import argparse
import json
import sys
from bigdata_toolkit import (
AnnotatedSearcher,
BigdataClient,
CostModel,
CostTracker,
EntityResolver,
StructuredDataREST,
rc,
)
def _show(title: str, obj, max_chars: int = 600) -> None:
print(f"\n{'='*60}\n{title}\n{'='*60}")
try:
s = json.dumps(obj, ensure_ascii=False, default=str)
except TypeError:
s = str(obj)
print(s[:max_chars] + (" ..." if len(s) > max_chars else ""))
def main() -> int:
ap = argparse.ArgumentParser(description="bigdata_toolkit probe example")
ap.add_argument(
"--with-search",
action="store_true",
help="额外跑一次 search(按 chunk 计费,~1 query_unit)",
)
args = ap.parse_args()
# ---- 0. 统一客户端(key 从 env 读,绝不硬编码) ----
client = BigdataClient() # 缺 BIGDATA_API_KEY 会 fail-fast
tracker = CostTracker(client)
resolver = EntityResolver(client)
rest = StructuredDataREST(client)
quota0 = rc(lambda: tracker.quota())
_show("[0] 起始配额(chunk 级,1 qu = 10 chunks)", quota0)
# ---- 1. 实体解析(SDK KG):美股英文名 + A 股 ISIN crosswalk ----
aapl_id = rc(lambda: resolver.resolve_id("Apple"))
print(f"\n[1a] Apple -> rp_entity_id = {aapl_id}")
# A 股:中文名直查会 0 命中,演示用 ISIN crosswalk(茅台)
moutai = rc(lambda: resolver.resolve_by_isin(["CNE0000018R8"]))
_show("[1b] 贵州茅台 ISIN(CNE0000018R8) crosswalk", moutai)
moutai_id = moutai[0].get("id") if moutai and moutai[0] else None
# ---- 2. SDK 缺失的前瞻财报日历(REST 逃生舱) ----
if aapl_id:
cal = rc(lambda: rest.events_calendar(
aapl_id,
categories=["earnings-call"],
start_date="2026-06-01",
end_date="2026-12-31",
limit=3,
))
# 只看顶层结构 + 第一条,避免刷屏
top_keys = list(cal.keys()) if isinstance(cal, dict) else type(cal).__name__
_show("[2] 前瞻财报日历 events-calendar(REST)顶层 keys", top_keys)
# ---- 3. SDK 缺失的前瞻一致预期(REST 逃生舱) ----
if aapl_id:
try:
est = rc(lambda: rest.analyst_estimates(aapl_id, period="quarter", limit=3))
top = list(est.keys()) if isinstance(est, dict) else type(est).__name__
_show("[3] 前瞻一致预期 analyst-estimates(REST)顶层 keys", top)
except Exception as e: # endpoint 半文档化,schema 可能漂移
print(f"\n[3] analyst-estimates 调用异常(半文档化 endpoint): "
f"{type(e).__name__}: {str(e)[:160]}")
# ---- 4. A 股结构化数据可用性验证(茅台 surprise) ----
if moutai_id:
try:
surp = rc(lambda: rest.latest_surprise(moutai_id))
top = list(surp.keys()) if isinstance(surp, dict) else type(surp).__name__
_show("[4] 茅台 latest-surprise(REST,验证 A 股结构面可用)顶层 keys", top)
except Exception as e:
print(f"\n[4] 茅台 surprise 异常: {type(e).__name__}: {str(e)[:160]}")
# ---- 5. 成本外推模型(纯计算,演示冷启动预算否决判断) ----
model = CostModel(chunk_limit_per_query=500, tier="fast")
est_poc = model.estimate(n_entities=20, n_windows=1)
est_full = model.estimate(n_entities=100, n_windows=12) # 100 标的 × 3 年季度
_show("[5a] 冷启动成本外推 · PoC(20 标的单快照)", est_poc)
_show("[5b] 冷启动成本外推 · 全量(100 标的 × 3 年季度)", est_full)
if est_full["pct_of_trial_quota"] > 100:
print(f" ⚠️ 全量 backfill 需 {est_full['pct_of_trial_quota']}% trial 配额 "
f"→ trial 做不了,需要更大的付费配额")
# ---- 6.(可选)带标注 chunk 抽取(按 chunk 计费,显式开启) ----
if args.with_search and aapl_id:
rc(lambda: tracker.snapshot())
searcher = AnnotatedSearcher(client)
docs = rc(lambda: searcher.search_entity(aapl_id, keyword="revenue", chunk_limit=10))
n_chunks = sum(len(d.get("chunks", [])) for d in docs)
print(f"\n[6] search 返回 {len(docs)} docs / {n_chunks} chunks")
if docs and docs[0].get("chunks"):
ch = docs[0]["chunks"][0]
text = ch.get("text") or ""
print(f" 首 chunk sentiment={ch.get('sentiment')} "
f"entities={len(ch.get('entities') or [])} text[:80]={text[:80]!r}")
_show("[6] search 实际消耗 delta", rc(lambda: tracker.delta()))
else:
print("\n[6] search 已跳过(加 --with-search 开启,按 chunk 计费)")
quota1 = rc(lambda: tracker.quota())
print(f"\n[*] 结束配额 used_chunks={quota1['used_chunks']} "
f"(起始 {quota0['used_chunks']}, 本次净增 "
f"{quota1['used_chunks'] - quota0['used_chunks']} chunks)")
return 0
if __name__ == "__main__":
sys.exit(main())