@yorha2b-lab/autodev 5.4.0 → 5.5.1

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.
@@ -0,0 +1,159 @@
1
+ import os
2
+ import numpy as np
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import seaborn as sns
6
+ from sklearn.cluster import DBSCAN
7
+ from sklearn.preprocessing import StandardScaler
8
+
9
+
10
+ def sigmoid(x):
11
+ """
12
+ 概率平滑函数:
13
+ 避免指标达到某个值后直接封顶,
14
+ 让异常程度呈渐进变化。
15
+ """
16
+ return 1 / (1 + np.exp(-x))
17
+
18
+
19
+ def map_rank(cluster_id):
20
+ """
21
+ DBSCAN 的 cluster 数量不是固定的,
22
+ 不能写死 0/1/2,否则新增聚类会出现 NaN。
23
+ """
24
+ if cluster_id == -1:
25
+ return 'Legendary'
26
+ if cluster_id == 0:
27
+ return 'Veteran'
28
+ return f'Tactical Unit {cluster_id}'
29
+
30
+
31
+ def execute_deep_intelligence():
32
+
33
+ print("🤖 Pod 042: 启动‘全量情报融合协议’...")
34
+
35
+ clone_path = 'ghrs-data/clones_ledger.csv'
36
+ view_path = 'ghrs-data/views_ledger.csv'
37
+
38
+ if not os.path.exists(clone_path) or not os.path.exists(view_path):
39
+ print("⚠️ 数据账本缺失,取消分析。")
40
+ return
41
+
42
+ # 1. 物理对账
43
+ df_c = pd.read_csv(clone_path)
44
+ df_v = pd.read_csv(view_path)
45
+
46
+ df = pd.merge(df_c, df_v, on='date', how='inner').fillna(0)
47
+
48
+ # ==================================================
49
+ # 2. 特征工程
50
+ # ==================================================
51
+
52
+ # 访问转化强度
53
+ df['ratio'] = (df['clones'] / df['views'].replace(0, 1))
54
+
55
+ # Github 行为天然长尾,因此进入 Log 空间
56
+ df['log_volume'] = np.log1p(df['clones'])
57
+ df['log_intensity'] = np.log1p(df['ratio'])
58
+
59
+ # ==================================================
60
+ # 3. 自动化概率审计
61
+ # ==================================================
62
+
63
+ # 原始 ratio 越高,越像自动化行为
64
+ ratio_score = sigmoid(df['ratio'] - 3)
65
+
66
+ # 单日爆发越高,异常概率越高
67
+ burst_score = sigmoid((df['clones'] - 100) / 100)
68
+
69
+ # 综合异常系数
70
+ df['bot_prob'] = (ratio_score * 0.6 + burst_score * 0.4)
71
+
72
+ # ==================================================
73
+ # 4. DBSCAN 行为聚类
74
+ # ==================================================
75
+ X = StandardScaler().fit_transform(df[['log_volume', 'log_intensity']])
76
+ db = DBSCAN(eps=0.4, min_samples=3).fit(X)
77
+ df['cluster'] = db.labels_
78
+
79
+ # ==================================================
80
+ # 5. 战力结算
81
+ # ==================================================
82
+ bot_clones = (df['clones'] * df['bot_prob']).sum()
83
+ total_clones = df['clones'].sum()
84
+ human_clones = max(0, total_clones - bot_clones)
85
+ df['rank'] = df['cluster'].apply(map_rank)
86
+ rank_counts = (df['rank'].value_counts())
87
+
88
+ # ==================================================
89
+ # 6. 全频道视觉矩阵
90
+ # ==================================================
91
+
92
+ plt.style.use('dark_background')
93
+ fig = plt.figure(figsize=(24, 8))
94
+
95
+ gs = fig.add_gridspec(1, 3, width_ratios=[1, 1.2, 1.8])
96
+
97
+ # ----------------------------
98
+ # A. 自动化组成
99
+ # ----------------------------
100
+
101
+ ax1 = fig.add_subplot(gs[0])
102
+
103
+ ax1.pie(
104
+ [human_clones, bot_clones],
105
+ labels=['Human', 'Machine'],
106
+ autopct='%1.1f%%',
107
+ startangle=90,
108
+ pctdistance=0.85,
109
+ explode=(0.05, 0)
110
+ )
111
+
112
+ ax1.add_artist(plt.Circle((0, 0), 0.70, fc='#0d1117'))
113
+ ax1.set_title("Operational Composition", color='#33cc33', pad=20)
114
+
115
+ # ----------------------------
116
+ # B. 行为层级
117
+ # ----------------------------
118
+
119
+ ax2 = fig.add_subplot(gs[1])
120
+ sns.barplot(x=rank_counts.index, y=rank_counts.values,
121
+ palette='viridis', ax=ax2)
122
+
123
+ ax2.set_title("Commander Hierarchy", color='#0066ff', pad=20)
124
+
125
+ ax2.set_ylabel("Days Count")
126
+
127
+ ax2.grid(axis='y', alpha=0.1)
128
+
129
+ # ----------------------------
130
+ # C. 行为拓扑
131
+ # ----------------------------
132
+
133
+ ax3 = fig.add_subplot(gs[2])
134
+
135
+ # sqrt 缩放避免极端 clone 撑爆气泡
136
+ bubble_size = (np.sqrt(df['clones'] + 1) * 20)
137
+ ax3.scatter(
138
+ df['log_volume'],
139
+ df['log_intensity'],
140
+ c=df['cluster'],
141
+ cmap='coolwarm',
142
+ s=bubble_size,
143
+ alpha=0.6,
144
+ edgecolors='w'
145
+ )
146
+ ax3.set_title("Sovereign Logistic Matrix (Log Space)",
147
+ color='#ff00ff', pad=20)
148
+ ax3.set_xlabel("Log(Total Clones)")
149
+ ax3.set_ylabel("Log(Intensity)")
150
+ ax3.grid(alpha=0.1)
151
+ plt.tight_layout()
152
+ os.makedirs('plots', exist_ok=True)
153
+ plt.savefig('plots/bunker_intelligence_fusion.png', dpi=120)
154
+
155
+ print("✅ 全量情报视觉矩阵封存成功!")
156
+
157
+
158
+ if __name__ == "__main__":
159
+ execute_deep_intelligence()
@@ -33,9 +33,7 @@ def assemble_readme():
33
33
  ![Peak Recon](./plots/bunker_peak_recon.png)
34
34
 
35
35
  ### 🧠 4. 深度情报审计 (Intelligence Intelligence)
36
- | 成分分析 (Meat vs Machine) | 战力梯度 (Hierarchy) |
37
- | :---: | :---: |
38
- | ![Bot](./plots/bot_composition.png) | ![Cluster](./plots/commander_profiles.png) |
36
+ ![Fusion](./plots/bunker_intelligence_fusion.png)
39
37
 
40
38
  #### 🛰️ 流量来源实时追踪
41
39
  {ref_table}
@@ -181,43 +181,87 @@ def intelligence_grid():
181
181
  plt.savefig('plots/bunker_intelligence_grid.png', dpi=100)
182
182
 
183
183
 
184
- def load_clean(path, col):
184
+ def load_clean(path, col_name):
185
185
  df = pd.read_csv(path)
186
186
  df['date'] = pd.to_datetime(df['date'], errors='coerce')
187
187
  df = df.dropna(subset=['date']).copy()
188
- df[col] = pd.to_numeric(df[col.lower()], errors='coerce').fillna(0)
189
- df['uniques'] = pd.to_numeric(df['uniques'], errors='coerce').fillna(0)
190
- return df[['date', col, 'uniques']]
188
+
189
+ # 物理强转数字
190
+ df[col_name] = pd.to_numeric(
191
+ df[col_name.lower()], errors='coerce').fillna(0)
192
+
193
+ # 💡 核心修正:直接在这里把 uniques 重命名为 [类别]_Uniques
194
+ # 这样合并后,列名就是固定的 'Clones_Uniques' 和 'Views_Uniques'
195
+ new_unique_name = f"{col_name}_Uniques"
196
+ df[new_unique_name] = pd.to_numeric(
197
+ df['uniques'], errors='coerce').fillna(0)
198
+
199
+ return df[['date', col_name, new_unique_name]]
191
200
 
192
201
 
193
202
  def main_dashboard(df_c, df_v):
203
+ # 💡 1. 数据融合与脱水
194
204
  df = pd.merge(df_c, df_v, on='date', how='outer').fillna(
195
205
  0).sort_values('date')
196
206
  df['cumulative'] = df['Clones'].cumsum()
197
- df['ratio'] = df['Clones'] / df['uniques'].replace(0, 1)
198
- df['clones_ma7'] = df['Clones'].rolling(window=7, min_periods=1).mean()
207
+ df['ratio'] = df['Clones'] / \
208
+ df['Views_Uniques'].replace(0, 1)
209
+
210
+ # 💡 2. 核心算法注入:计算“信号纯度” (Purity)
211
+ df['cumulative'] = df['Clones'].cumsum()
212
+
213
+ # 计算“信号纯度”:克隆数 / 访客数
214
+ df['ratio'] = df['Clones'] / df['Views_Uniques'].replace(0, 1)
215
+
216
+ # 算法:(比例/10 * 0.6) + (总量/500 * 0.4)
217
+ df['bot_prob'] = (df['ratio'] / 10).clip(upper=1) * 0.6 + \
218
+ (df['Clones'] / 500).clip(upper=1) * 0.4
219
+ df['purity'] = (1.0 - df['bot_prob']) * 100
199
220
 
200
- fig1 = plt.figure(figsize=(12, 10))
201
- gs1 = fig1.add_gridspec(3, 1)
221
+ # 💡 3. 画布物理扩容:由 3 行 1 列 升级为 4 行 1 列
222
+ fig1 = plt.figure(figsize=(12, 14)) # 增加高度以容纳四个雷达
223
+ gs1 = fig1.add_gridspec(4, 1)
224
+
225
+ # --- 子图 1: 实时侦察 (Views vs Clones) ---
202
226
  ax1 = fig1.add_subplot(gs1[0])
203
227
  ax1.plot(df['date'].tail(30), df['Views'].tail(
204
228
  30), alpha=0.5, ls='--', label='Views (Web)')
205
229
  ax1.plot(df['date'].tail(30), df['Clones'].tail(30),
206
230
  color='#33cc33', lw=2, label='Clones (Terminal)')
207
231
  ax1.set_title(
208
- 'Strategic Recon: Views vs Clones (Last 30D)', color='#33cc33')
232
+ 'Strategic Recon: Web Visitors vs Terminal Commandos (30D)', color='#33cc33')
209
233
  ax1.legend(loc='upper left', frameon=True, fontsize='small')
234
+
235
+ # --- 子图 2: 累计荣光 (Growth) ---
210
236
  ax2 = fig1.add_subplot(gs1[1])
211
- ax2.fill_between(df['date'], df['cumulative'],
212
- color='#0066ff', alpha=0.2)
237
+ ax2.fill_between(df['date'], df['cumulative'], color='#0066ff', alpha=0.2)
213
238
  ax2.plot(df['date'], df['cumulative'], color='#0066ff', lw=3)
214
239
  ax2.set_title('Bunker Glory: Total Cumulative Growth', color='#0066ff')
215
- ax3 = fig1.add_subplot(gs1[2])
216
- pivot = df.assign(week=df['date'].dt.isocalendar().week, day=df['date'].dt.day_name()).pivot_table(index='day', columns='week',
217
- values='Clones', aggfunc='sum').fillna(0).reindex(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
240
+
241
+ # --- 💡 子图 3 [核心新增]: 信号纯度审计 (Signal Purity) ---
242
+ ax_p = fig1.add_subplot(gs1[2])
243
+ # 使用渐变紫色,代表地堡的“骇入感知”
244
+ ax_p.fill_between(df['date'].tail(45), df['purity'].tail(
245
+ 45), color='#ff00ff', alpha=0.1)
246
+ ax_p.plot(df['date'].tail(45), df['purity'].tail(45),
247
+ color='#ff00ff', lw=1.5, label='Signal Purity %')
248
+ ax_p.set_ylim(0, 105) # 留点空白放标题
249
+ ax_p.axhline(y=50, color='#444', linestyle=':', alpha=0.5) # 50% 警戒线
250
+ ax_p.set_title(
251
+ 'Neural Cloud Integrity: Human Signal Purity Audit (%)', color='#ff00ff')
252
+ ax_p.legend(loc='lower left', fontsize='x-small')
253
+
254
+ # --- 子图 4: 作战热力图 (Heatmap) ---
255
+ ax3 = fig1.add_subplot(gs1[3])
256
+ pivot = df.assign(week=df['date'].dt.isocalendar().week, day=df['date'].dt.day_name()).pivot_table(
257
+ index='day', columns='week', values='Clones', aggfunc='sum'
258
+ ).fillna(0).reindex(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
259
+
218
260
  sns.heatmap(pivot, cmap='Greens', ax=ax3,
219
261
  cbar=False, lw=2, linecolor='#1a1a1a')
220
- ax3.set_title('Deployment Matrix: All-Time Activity', color='#33cc33')
262
+ ax3.set_title(
263
+ 'Global Deployment Heatmap: Strategic Activity Matrix', color='#33cc33')
264
+
221
265
  plt.tight_layout()
222
266
  plt.savefig('plots/bunker_main_v7.png', dpi=120)
223
267
 
@@ -35,7 +35,7 @@ jobs:
35
35
  python-version: '3.10'
36
36
 
37
37
  - name: Install Dependencies
38
- run: pip install matplotlib pandas seaborn scipy numpy requests
38
+ run: pip install matplotlib pandas seaborn scipy numpy requests scikit-learn
39
39
 
40
40
  # 💡 步骤 3:运行脚本,注意现在的相对路径!
41
41
  # 我们在当前根目录运行,调用 scripts_repo 里的脚本,去处理 data_repo 里的数据
@@ -48,8 +48,7 @@ jobs:
48
48
  run: |
49
49
  cd data_repo
50
50
  # 执行“肉机比”扫描与“军衔”聚类分析
51
- python ../scripts_repo/.github/scripts/analyze/bot_detect.py
52
- python ../scripts_repo/.github/scripts/analyze/cluster.py
51
+ python ../scripts_repo/.github/scripts/analyze/deep_intelligence.py
53
52
 
54
53
  - name: '📈 Step 3: Visualization Rendering'
55
54
  run: |
package/bin/autodev.js CHANGED
@@ -4,9 +4,11 @@ const path = require('path')
4
4
  const chalk = require('chalk')
5
5
  const pkg = require('../package.json')
6
6
  const { program } = require('commander')
7
+
8
+ const { discover } = require('../src/utils/foundation')
7
9
  const { local, matrixEffect, bootSequence } = require('../src/utils/ux')
8
10
 
9
- const dialogs = require('../src/bootstrap/registry')({ dir: path.join(__dirname, '../src/dialogs') })
11
+ const dialogs = discover(path.join(__dirname, '../src/dialogs'))
10
12
  const dialog = dialogs[local] ?? dialogs['EN-US']
11
13
 
12
14
  program
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "5.4.0",
3
+ "version": "5.5.1",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -27,9 +27,9 @@ module.exports = {
27
27
  openAI: require('./openai')(),
28
28
  core: require('../utils/core'),
29
29
  menus: foundation.getExistingMenus(),
30
+ handlers: foundation.discover(path.join(__dirname, '../handlers')),
30
31
  handlebars: require('./handlebar')({ config, template, ...foundation }),
31
- handlers: require('./registry')({ dir: path.join(__dirname, '../handlers') }),
32
- prompts: require('./registry')({ dir: path.join(__dirname, `../framework/${template}/prompts`) }),
32
+ prompts: foundation.discover(path.join(__dirname, `../framework/${template}/prompts`)),
33
33
  }
34
34
 
35
35
  require('./foundation')(accessPoint)
@@ -5,23 +5,23 @@ module.exports = () => {
5
5
 
6
6
  const createMember = ({ name }) => ({
7
7
  start(text) {
8
- const spinner = ora({ text: chalk.cyan(`\n${name} ${text}`) }).start()
8
+ const spinner = ora({ text: chalk.cyan(`${name} ${text}\n`) }).start()
9
9
  return spinner
10
10
  },
11
11
  fail(spinner, text) {
12
- spinner.fail(chalk.red(`\n${name} ${text}`))
12
+ spinner.fail(chalk.red(`${name} ${text}\n`))
13
13
  },
14
14
  report(text, color = 'yellow') {
15
- console.log(chalk[color](`\n${name} ${text}`))
15
+ console.log(chalk[color](`${name} ${text}\n`))
16
16
  },
17
17
  update(spinner, text) {
18
- spinner.text = chalk.cyan(`\n${name} ${text}`)
18
+ spinner.text = chalk.cyan(`${name} ${text}\n`)
19
19
  },
20
20
  warning(spinner, text) {
21
- spinner.warn(chalk.yellow(`\n${name} ${text}`))
21
+ spinner.warn(chalk.yellow(`${name} ${text}\n`))
22
22
  },
23
23
  success(spinner, text) {
24
- spinner.succeed(chalk.green(`\n${name} ${text}`))
24
+ spinner.succeed(chalk.green(`${name} ${text}\n`))
25
25
  },
26
26
  })
27
27
 
@@ -38,7 +38,7 @@ const onTabChange = key => {
38
38
  {{#if hasExpandable}}
39
39
  const onExpand = async (expanded, record) => {
40
40
  if (expanded) {
41
- setExpandedRowKeys(prev=>[...prev, record[rowKey])
41
+ setExpandedRowKeys(prev=>[...prev, record[rowKey]])
42
42
  } else {
43
43
  setExpandedRowKeys(prev=>prev.filter(item => item !== record[rowKey]))
44
44
  }
@@ -5,7 +5,7 @@ module.exports = {
5
5
  watch: 'screenShot',
6
6
  async handle(filePath) {
7
7
 
8
- const { llm, menus, yorha, dialog, config, prompts, generator, foundation } = require('../bootstrap').get()
8
+ const { llm, menus, yorha, dialog, config, prompts, template, generator, foundation } = require('../bootstrap').get()
9
9
 
10
10
  const { page } = prompts
11
11
  const { nineS, pod042 } = yorha
@@ -37,7 +37,7 @@ module.exports = {
37
37
  pageConfig = require('../../example/example.json')
38
38
  } else {
39
39
  pod042.update(spinner, dialog.pod042.uploadVisualMetadata)
40
- pageConfig = await recognizePage({ prompt: page(fileName), filePath })
40
+ pageConfig = await recognizePage({ prompt: page(fileName), filePath, schema: require(`../framework/${template}/schema/page.json`) })
41
41
  }
42
42
 
43
43
  fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig }))
@@ -62,6 +62,9 @@ module.exports = {
62
62
  }
63
63
 
64
64
  } catch (error) {
65
+ if (fs.existsSync(targetDir)) {
66
+ fs.rmSync(targetDir, { recursive: true, force: true })
67
+ }
65
68
  pod042.fail(spinner, dialog.pod042.constructionAborted(error))
66
69
  }
67
70
  }
@@ -20,7 +20,7 @@ module.exports = {
20
20
  try {
21
21
  pod042.update(spinner, dialog.pod042.extractingUiMetadata)
22
22
 
23
- const pageConfig = await recognizePage({ prompt, filePath, taskType: 'part' })
23
+ const pageConfig = await recognizePage({ prompt, filePath })
24
24
 
25
25
  const { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
26
26
 
@@ -32,7 +32,7 @@ const askAI = async ({ model, yorha, dialog, openAI, messages, response_format =
32
32
  }
33
33
  }
34
34
 
35
- module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
35
+ module.exports = ({ config, yorha, openAI, dialog, prompts }) => {
36
36
 
37
37
  const sharp = require('sharp')
38
38
 
@@ -65,19 +65,7 @@ module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
65
65
  ]
66
66
  })
67
67
  },
68
- alignResponseFields: async ({ responseStr, resourceStr }) => {
69
- return askAI({
70
- yorha,
71
- openAI,
72
- dialog,
73
- model: textModel,
74
- messages: [
75
- { role: 'system', content: API_DESIGNER },
76
- { role: 'user', content: api({ responseStr, resourceStr }) }
77
- ]
78
- })
79
- },
80
- recognizePage: async ({ prompt, filePath, taskType = 'page' }) => {
68
+ recognizePage: async ({ prompt, filePath, schema }) => {
81
69
  const compressedBuffer = await sharp(filePath)
82
70
  .resize(1280, null, { withoutEnlargement: true })
83
71
  .jpeg({ quality: 80 })
@@ -99,7 +87,19 @@ module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
99
87
  ]
100
88
  }
101
89
  ],
102
- response_format: taskType === 'page' ? { type: 'json_schema', strict: true, json_schema: require(`../framework/${template}/schema/page.json`) } : { type: 'json_object' }
90
+ response_format: schema ? { strict: true, type: 'json_schema', json_schema: schema } : { type: 'json_object' }
91
+ })
92
+ },
93
+ alignResponseFields: async ({ responseStr, resourceStr }) => {
94
+ return askAI({
95
+ yorha,
96
+ openAI,
97
+ dialog,
98
+ model: textModel,
99
+ messages: [
100
+ { role: 'system', content: API_DESIGNER },
101
+ { role: 'user', content: api({ responseStr, resourceStr }) }
102
+ ]
103
103
  })
104
104
  },
105
105
  }
@@ -11,7 +11,6 @@ const fs = require('fs')
11
11
  const path = require('path')
12
12
  const stringify = require('json-stringify-pretty-compact')
13
13
 
14
-
15
14
  /**
16
15
  * 获取项目配置信息
17
16
  * 优先读取项目根目录的 config.js,如果不存在则使用默认配置
@@ -63,4 +62,6 @@ const copyTemplateDir = (template, templateSubDir, targetSubDir) => {
63
62
 
64
63
  const contextStringify = ({ context, indent = 4, maxLength = 200 }) => stringify.default(context, { indent, maxLength })
65
64
 
66
- module.exports = { getConfig, getExistingMenus, copyTemplateDir, contextStringify }
65
+ const discover = dir => Object.fromEntries(fs.readdirSync(dir).filter(file => file.endsWith('.js')).map(file => [path.basename(file, '.js'), require(path.join(dir, file))]))
66
+
67
+ module.exports = { discover, getConfig, getExistingMenus, copyTemplateDir, contextStringify }
@@ -1,43 +0,0 @@
1
- import os
2
- import pandas as pd
3
- import matplotlib.pyplot as plt
4
-
5
-
6
- def plot_bot_composition():
7
- print('🤖 Pod 042: 正在绘制‘肉机成分分析图’...')
8
- df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
9
- df_v = pd.read_csv('ghrs-data/views_ledger.csv')
10
- df = pd.merge(df_c, df_v, on='date', how='inner')
11
-
12
- # 算法:Shadow Ratio > 5 判定为机器
13
- df['is_bot'] = (df['clones'] / df['views'].replace(0, 1)) > 5
14
- bot_clones = df[df['is_bot']]['clones'].sum()
15
- total_clones = df['clones'].sum()
16
- human_clones = total_clones - bot_clones
17
-
18
- # 💡 绘图:地堡级甜甜圈图
19
- plt.style.use('dark_background')
20
- fig, ax = plt.subplots(figsize=(8, 8))
21
-
22
- data = [human_clones, bot_clones]
23
- labels = ['Human Commanders', 'Machine Lifeforms']
24
- colors = ['#33cc33', '#444444'] # 地堡绿 vs 灰
25
-
26
- wedges, texts, autotexts = ax.pie(data, labels=labels, autopct='%1.1f%%',
27
- startangle=90, colors=colors, pctdistance=0.85,
28
- explode=(0.05, 0), textprops={'color': 'w'})
29
-
30
- # 画个中间的黑洞,变成甜甜圈
31
- centre_circle = plt.Circle((0, 0), 0.70, fc='#0d1117')
32
- fig.gca().add_artist(centre_circle)
33
-
34
- ax.set_title('Operational Composition: Meat vs Machine',
35
- color='#33cc33', fontsize=14)
36
- plt.tight_layout()
37
- os.makedirs('plots', exist_ok=True)
38
- plt.savefig('plots/bot_composition.png', dpi=100)
39
- print('✅ 甜甜圈图封存成功。')
40
-
41
-
42
- if __name__ == '__main__':
43
- plot_bot_composition()
@@ -1,40 +0,0 @@
1
- import pandas as pd
2
- import seaborn as sns
3
- import matplotlib.pyplot as plt
4
-
5
-
6
- def plot_commander_profiles():
7
- print('🤖 Pod 042: 正在绘制‘指挥官军衔分布图’...')
8
- df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
9
- df_c['intensity'] = df_c['clones'] / df_c['uniques'].replace(0, 1)
10
-
11
- # 定义军衔逻辑
12
- def get_rank(row):
13
- if row['intensity'] > 5:
14
- return 'Industrial (CI/CD)'
15
- if row['intensity'] > 1.5:
16
- return 'Veteran (Hardcore)'
17
- return 'Recruit (Fresh)'
18
-
19
- df_c['rank'] = df_c.apply(get_rank, axis=1)
20
- rank_counts = df_c['rank'].value_counts()
21
-
22
- # 💡 绘图:战力梯度图
23
- plt.style.use('dark_background')
24
- plt.figure(figsize=(10, 6))
25
-
26
- # 用 seaborn 画出更有质感的柱状图
27
- ax = sns.barplot(x=rank_counts.index,
28
- y=rank_counts.values, palette='viridis')
29
-
30
- plt.title('Commander Hierarchy Distribution', color='#0066ff', fontsize=14)
31
- plt.ylabel('Node Count', color='#888')
32
- plt.grid(axis='y', color='#333', linestyle='--', alpha=0.5)
33
-
34
- plt.tight_layout()
35
- plt.savefig('plots/commander_profiles.png', dpi=100)
36
- print('✅ 军衔分布图封存成功。')
37
-
38
-
39
- if __name__ == '__main__':
40
- plot_commander_profiles()
@@ -1,14 +0,0 @@
1
- module.exports = ({ dir }) => {
2
-
3
- const fs = require('fs')
4
- const path = require('path')
5
-
6
- return Object.fromEntries(
7
- fs.readdirSync(dir)
8
- .filter(file => file.endsWith('.js'))
9
- .map(file => [
10
- path.basename(file, '.js'),
11
- require(path.join(dir, file))
12
- ])
13
- )
14
- }