@petercjl/taobao-ai-ops 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +30 -22
  2. package/package.json +2 -7
  3. package/requirements.txt +1 -0
  4. package/skills/taobao-ai-operations/SKILL.md +8 -1
  5. package/src/cli.mjs +16 -6
  6. package/src/components.mjs +73 -0
  7. package/src/core.mjs +5 -1
  8. package/src/runtime.mjs +18 -16
  9. package/src/skill-manager.mjs +4 -4
  10. package/src/update.mjs +5 -5
  11. package/src/workflow.mjs +3 -3
  12. package/suite-manifest.json +186 -10
  13. package/skills/taobao-search-product-form/SKILL.md +0 -74
  14. package/skills/taobao-search-product-form/adapters/codex.json +0 -139
  15. package/skills/taobao-search-product-form/adapters/sealseek.json +0 -24
  16. package/skills/taobao-search-product-form/agents/openai.yaml +0 -3
  17. package/skills/taobao-search-product-form/capabilities.json +0 -148
  18. package/skills/taobao-search-product-form/references/SCHEMA.md +0 -3
  19. package/skills/taobao-search-product-form/references/index.md +0 -10
  20. package/skills/taobao-search-product-form/references/log.md +0 -35
  21. package/skills/taobao-search-product-form/references/queries/evaluate-white-label-forms.md +0 -3
  22. package/skills/taobao-search-product-form/references/queries/identify-advertisers.md +0 -5
  23. package/skills/taobao-search-product-form/references/queries/identify-geography.md +0 -5
  24. package/skills/taobao-search-product-form/references/queries/identify-price-bands.md +0 -3
  25. package/skills/taobao-search-product-form/references/queries/identify-product-forms.md +0 -3
  26. package/skills/taobao-search-product-form/references/queries/identify-title-roots.md +0 -5
  27. package/skills/taobao-search-product-form/references/report-output.md +0 -23
  28. package/skills/taobao-search-product-form/references/source-manifest.md +0 -37
  29. package/skills/taobao-search-product-form/references/title-lexicon.json +0 -55
  30. package/skills/taobao-search-product-form/references/topics/advertiser-analysis-method.md +0 -43
  31. package/skills/taobao-search-product-form/references/topics/geography-analysis-method.md +0 -23
  32. package/skills/taobao-search-product-form/references/topics/price-band-analysis-method.md +0 -27
  33. package/skills/taobao-search-product-form/references/topics/title-root-analysis-method.md +0 -37
  34. package/skills/taobao-search-product-form/references/topics/visual-form-method.md +0 -31
  35. package/skills/taobao-search-product-form/references/topics/white-label-evidence.md +0 -38
  36. package/skills/taobao-search-product-form/references/workflow-ledger.md +0 -28
  37. package/skills/taobao-search-product-form/report_runtime/VERSION +0 -1
  38. package/skills/taobao-search-product-form/report_runtime/renderer.py +0 -485
  39. package/skills/taobao-search-product-form/report_runtime/templates/workbench.html +0 -67
  40. package/skills/taobao-search-product-form/report_runtime/validator.py +0 -117
  41. package/skills/taobao-search-product-form/scripts/analyze.py +0 -119
  42. package/skills/taobao-search-product-form/scripts/analyze_advertisers.py +0 -352
  43. package/skills/taobao-search-product-form/scripts/analyze_geography.py +0 -316
  44. package/skills/taobao-search-product-form/scripts/analyze_price_bands.py +0 -257
  45. package/skills/taobao-search-product-form/scripts/analyze_title_roots.py +0 -327
  46. package/skills/taobao-search-product-form/scripts/assemble_opportunity_evidence.py +0 -322
  47. package/skills/taobao-search-product-form/scripts/build_report_viewmodel.py +0 -822
  48. package/skills/taobao-search-product-form/scripts/build_visual_review_viewmodel.py +0 -177
  49. package/skills/taobao-search-product-form/scripts/clean_search_export.mjs +0 -61
  50. package/skills/taobao-search-product-form/scripts/cluster_visual_forms.py +0 -193
  51. package/skills/taobao-search-product-form/scripts/compile_style_prototypes.py +0 -115
  52. package/skills/taobao-search-product-form/scripts/compile_visual_review.py +0 -60
  53. package/skills/taobao-search-product-form/scripts/compile_visual_selection.py +0 -148
  54. package/skills/taobao-search-product-form/scripts/prepare.py +0 -180
  55. package/skills/taobao-search-product-form/scripts/render_report.py +0 -31
  56. package/skills/taobao-search-product-form/scripts/validate_opportunity_cards.py +0 -84
  57. package/skills/taobao-search-product-form/scripts/validate_report_viewmodel.py +0 -152
  58. package/skills/taobao-search-product-form/scripts/visual_form_pipeline.py +0 -247
  59. package/skills/taobao-search-product-form/scripts/visual_observation_batches.py +0 -117
  60. package/skills/taobao-search-product-form/scripts/workflow_ledger.py +0 -177
  61. package/skills/yuce-category-opportunity-report/SKILL.md +0 -151
  62. package/skills/yuce-category-opportunity-report/adapters/codex.json +0 -113
  63. package/skills/yuce-category-opportunity-report/adapters/sealseek.json +0 -39
  64. package/skills/yuce-category-opportunity-report/agents/openai.yaml +0 -3
  65. package/skills/yuce-category-opportunity-report/assets/chart-views.js +0 -80
  66. package/skills/yuce-category-opportunity-report/assets/package.json +0 -1
  67. package/skills/yuce-category-opportunity-report/assets/report-template.html +0 -62
  68. package/skills/yuce-category-opportunity-report/capabilities.json +0 -48
  69. package/skills/yuce-category-opportunity-report/references/SCHEMA.md +0 -5
  70. package/skills/yuce-category-opportunity-report/references/data-contract.md +0 -40
  71. package/skills/yuce-category-opportunity-report/references/index.md +0 -6
  72. package/skills/yuce-category-opportunity-report/references/log.md +0 -29
  73. package/skills/yuce-category-opportunity-report/references/queries/assess-category-opportunity.md +0 -7
  74. package/skills/yuce-category-opportunity-report/references/source-manifest.md +0 -14
  75. package/skills/yuce-category-opportunity-report/references/topics/category-opportunity-method.md +0 -39
  76. package/skills/yuce-category-opportunity-report/scripts/build_report.py +0 -779
  77. package/skills/yuce-category-opportunity-report/scripts/market_routes.py +0 -139
@@ -1,139 +0,0 @@
1
- """Scale-invariant market segmentation and independent research queues."""
2
- import math
3
- from bisect import bisect_left, bisect_right
4
-
5
-
6
- DEFAULT_POLICY = {
7
- "capacityQuantiles": [0.4, 0.7, 0.9],
8
- "minYoy": 0.2, "minSixMonthYoy": 0.2, "minPositiveMonths": 10,
9
- "shortlistLimit": 6,
10
- "why": "以本一级类目完整三级类目的容量分布形成可复核起点;结合偏斜、并列和业务目标复核分位点。",
11
- }
12
- LABELS = {"large": "大市场增量型", "medium": "中等容量持续增长型",
13
- "small": "中小容量成长型", "tail": "相对小容量观察", "unknown": "未分档"}
14
-
15
-
16
- def quantile(values, p):
17
- if not values:
18
- return None
19
- position = (len(values) - 1) * p
20
- lo, hi = math.floor(position), math.ceil(position)
21
- return values[lo] + (values[hi] - values[lo]) * (position - lo)
22
-
23
-
24
- def validate_policy(supplied):
25
- policy = dict(DEFAULT_POLICY)
26
- if supplied is not None:
27
- if not isinstance(supplied, dict) or set(supplied) - set(policy):
28
- raise ValueError("路线配置只接受分位点、增长条件、名额和理由;容量不接受绝对金额")
29
- policy.update(supplied)
30
- if not isinstance(supplied.get("why"), str) or len(supplied["why"].strip()) < 8:
31
- raise ValueError("调整路线参数须说明类目分布与经营目标依据")
32
- qs = policy["capacityQuantiles"]
33
- number = lambda x: isinstance(x, (int, float)) and not isinstance(x, bool) and math.isfinite(x)
34
- if not isinstance(qs, list) or len(qs) != 3 or not all(number(q) for q in qs) or not 0 < qs[0] < qs[1] < qs[2] < 1:
35
- raise ValueError("capacityQuantiles 须为三个严格递增的 0 到 1 之间的分位点")
36
- for key in ("minYoy", "minSixMonthYoy"):
37
- if not number(policy[key]) or not 0 <= policy[key] <= 5:
38
- raise ValueError("增长门槛须为 0 到 5 之间的有限数值")
39
- if type(policy["minPositiveMonths"]) is not int or not 1 <= policy["minPositiveMonths"] <= 12:
40
- raise ValueError("增长月份须为 1 到 12 的整数")
41
- if type(policy["shortlistLimit"]) is not int or not 1 <= policy["shortlistLimit"] <= 8:
42
- raise ValueError("每条路线名额须为 1 到 8 的整数")
43
- return policy
44
-
45
-
46
- def classify(amount, cuts):
47
- # Equal amounts stay together, including on coincident boundaries.
48
- if amount >= cuts[2]:
49
- return "large"
50
- if amount >= cuts[1]:
51
- return "medium"
52
- if amount >= cuts[0]:
53
- return "small"
54
- return "tail"
55
-
56
-
57
- def build_routes(stats, supplied=None):
58
- policy = validate_policy(supplied)
59
- leaves = [x for x in stats if x["level"] == 3]
60
- complete = [x for x in leaves if x["complete"]]
61
- eligible_base = [x for x in complete if x["recentAmount"] > 0]
62
- amounts = sorted(x["recentAmount"] for x in eligible_base)
63
- cuts = [quantile(amounts, p) for p in policy["capacityQuantiles"]]
64
- total = sum(amounts)
65
- root = next(x for x in stats if x["level"] == 1)
66
- warnings = []
67
- if len(amounts) < 10:
68
- warnings.append("有效类目少于10个,分位分档不稳定;保留空路线,不凑数。")
69
- if amounts and len(set(cuts)) < 3:
70
- warnings.append("分界金额重合;同额类目归入同一较高档,部分路线可能为空。")
71
- for item in leaves:
72
- item.update(capacityBand="unknown", capacityLabel=LABELS["unknown"], capacityPercentile=None,
73
- sustainedGrowthIndex=None, routeRank=None, firstHalfYoy=None,
74
- growthAccelerationPp=None, top3PositiveIncrementShare=None)
75
- item["growthImpactIndex"] = (100 * max(item["increment"], 0) / root["recentAmount"]
76
- * item["positiveYoyMonths"] / 12
77
- if item["complete"] and root["recentAmount"] > 0 else None)
78
- reasons = []
79
- if not item["complete"]:
80
- reasons.append("缺少完整24个月")
81
- elif item["recentAmount"] <= 0:
82
- reasons.append("最近一年无正成交额")
83
- else:
84
- band = classify(item["recentAmount"], cuts)
85
- item["capacityBand"], item["capacityLabel"] = band, LABELS[band]
86
- left, right = bisect_left(amounts, item["recentAmount"]), bisect_right(amounts, item["recentAmount"])
87
- item["capacityPercentile"] = 100 * (left + (right - left) / 2) / len(amounts)
88
- m = item["monthlyAmounts"]
89
- before = sum(m[:6])
90
- item["firstHalfYoy"] = sum(m[12:18]) / before - 1 if before > 0 else None
91
- if item["sixMonthYoy"] is not None and item["firstHalfYoy"] is not None:
92
- item["growthAccelerationPp"] = 100 * (item["sixMonthYoy"] - item["firstHalfYoy"])
93
- increments = sorted((max(m[i + 12] - m[i], 0) for i in range(12)), reverse=True)
94
- item["top3PositiveIncrementShare"] = sum(increments[:3]) / sum(increments) if sum(increments) else None
95
- if item["yoy"] is not None and item["sixMonthYoy"] is not None:
96
- item["sustainedGrowthIndex"] = 100 * min(item["yoy"], item["sixMonthYoy"]) * item["positiveYoyMonths"] / 12
97
- if band == "tail":
98
- reasons.append("低于本类目相对容量下界")
99
- if item["yoy"] is None or item["yoy"] < policy["minYoy"]:
100
- reasons.append("全年增长未达标或基期为零")
101
- if item["sixMonthYoy"] is None or item["sixMonthYoy"] < policy["minSixMonthYoy"]:
102
- reasons.append("近6个月增长未达标或基期为零")
103
- if item["positiveYoyMonths"] < policy["minPositiveMonths"]:
104
- reasons.append("增长月份未达标")
105
- if any(word in item["path"][-1] for word in ("其他", "其它")):
106
- reasons.append("混合类目须先拆解构成")
107
- item["routeExclusionReasons"] = reasons
108
- routes = []
109
- for key in ("large", "medium", "small"):
110
- metric = "growthImpactIndex" if key == "large" else "sustainedGrowthIndex"
111
- members = [x for x in leaves if x["capacityBand"] == key]
112
- pool = [x for x in members if not x["routeExclusionReasons"] and x[metric] is not None]
113
- pool.sort(key=lambda x: (-x[metric], -x["positiveYoyMonths"], tuple(x["path"])))
114
- for rank, item in enumerate(pool, 1):
115
- item["routeRank"] = rank
116
- routes.append({"id": key, "label": LABELS[key], "metric": metric,
117
- "metricLabel": "持续增量贡献" if key == "large" else "持续增长强度",
118
- "bandCount": len(members), "poolCount": len(pool),
119
- "poolPaths": [x["path"] for x in pool],
120
- "candidatePaths": [x["path"] for x in pool[:policy["shortlistLimit"]]],
121
- "emptyReason": "本档没有满足数据与增长条件的类目,保留空名单。" if not pool else ""})
122
- # Sensitivity is diagnostic, never an automatic override or retrospective fit.
123
- sensitivity = []
124
- for offset in (-0.05, 0.05):
125
- qs = [p + offset for p in policy["capacityQuantiles"]]
126
- if not amounts or not 0 < qs[0] < qs[1] < qs[2] < 1:
127
- continue
128
- shifted = [quantile(amounts, p) for p in qs]
129
- moved = sum(classify(x["recentAmount"], shifted) != x["capacityBand"] for x in eligible_base)
130
- sensitivity.append({"quantiles": qs, "boundaryAmounts": shifted, "changedBandCount": moved})
131
- return {"policy": policy, "boundaryAmounts": cuts, "routes": routes,
132
- "distribution": {"completeCount": len(complete), "populationCount": len(amounts),
133
- "incompleteCount": len(leaves) - len(complete),
134
- "median": quantile(amounts, 0.5), "p10": quantile(amounts, 0.1),
135
- "p90": quantile(amounts, 0.9),
136
- "top10PercentGmvShare": sum(amounts[-max(1, math.ceil(len(amounts) * .1)):]) / total if total else None,
137
- "tailCount": sum(x["capacityBand"] == "tail" for x in leaves)},
138
- "sensitivity": sensitivity, "warnings": warnings,
139
- "competitionStatus": "未验证;容量与增长不能推断品牌竞争、白牌份额或利润"}