@yorha2b-lab/autodev 4.1.0 → 4.2.0
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.
- package/.github/scripts/analyze/bot_detect.py +5 -5
- package/.github/scripts/analyze/cluster.py +5 -5
- package/.github/scripts/collect/traffic.py +11 -11
- package/.github/scripts/deploy/publish.py +15 -15
- package/.github/scripts/render/dashboard.py +9 -9
- package/.github/workflows/bunker-intelligence.yml +4 -4
- package/bin/autodev.js +6 -5
- package/config.js +1 -1
- package/package.json +1 -1
- package/src/commands/handlers/api-handler.js +15 -10
- package/src/commands/handlers/page-handler.js +21 -19
- package/src/commands/handlers/part-handler.js +14 -11
- package/src/commands/watch.js +20 -18
- package/src/core/context.js +39 -52
- package/src/core/react-compiler.js +69 -85
- package/src/prompts/mock.js +1 -1
- package/src/prompts/react/api-linker.js +1 -1
- package/src/prompts/react/watch-api.js +1 -1
- package/src/prompts/react/watch-page.js +1 -0
- package/src/prompts/react/watch-part.js +1 -0
- package/src/services/api-linker.js +21 -59
- package/src/services/llm.js +64 -81
- package/src/services/proxy-tower.js +17 -12
- package/src/utils/{utils.js → core.js} +41 -165
- package/src/utils/infrastructure.js +102 -0
- package/src/utils/ux.js +115 -0
- package/templates/react/components/MyModalForm.js +1 -1
- package/templates/react/components/MyModalTable.js +1 -1
- package/templates/react/components/index.js +2 -2
- package/templates/react/handlebars/handleBlock.hbs +3 -2
- package/templates/react/handlebars/hookBlock.hbs +1 -0
- package/src/core/task-queue.js +0 -38
- /package/src/schema/{page.json → react/page.json} +0 -0
package/src/core/context.js
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const chalk = require('chalk')
|
|
4
|
+
const OpenAI = require('openai')
|
|
4
5
|
const Handlebars = require('handlebars')
|
|
5
6
|
const stringify = require('json-stringify-pretty-compact')
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(stringify.default(context, { indent: 4, maxLength })) : '[]')
|
|
8
|
+
const contextStringify = ({ context, indent = 4, maxLength = 200 }) => stringify.default(context, { indent, maxLength })
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Handlebars.registerHelper('raw', opt => opt.fn())
|
|
11
|
+
Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(contextStringify({ context, maxLength })) : '[]')
|
|
12
|
+
|
|
13
|
+
let instance = null
|
|
11
14
|
|
|
12
15
|
module.exports = {
|
|
13
|
-
|
|
14
|
-
* @description 执行中枢神经元初始化
|
|
15
|
-
*/
|
|
16
|
+
|
|
16
17
|
init: options => {
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
19
|
+
const template = options.template
|
|
20
|
+
const uxCtx = require('../utils/ux')
|
|
21
|
+
const coreCtx = require('../utils/core')
|
|
22
|
+
const infrastructureCtx = require('../utils/infrastructure')
|
|
23
|
+
|
|
24
|
+
const { language } = uxCtx
|
|
25
|
+
const { getConfig, getExistingMenus } = infrastructureCtx
|
|
20
26
|
|
|
21
27
|
const config = getConfig()
|
|
28
|
+
const { hbsDir } = config
|
|
29
|
+
|
|
22
30
|
const menus = getExistingMenus()
|
|
23
|
-
const template = options.template
|
|
24
31
|
const apiHandler = require('../commands/handlers/api-handler')
|
|
25
32
|
const pageHandler = require('../commands/handlers/page-handler')
|
|
26
33
|
const partHandler = require('../commands/handlers/part-handler')
|
|
27
|
-
const tplDir =
|
|
34
|
+
const tplDir = hbsDir !== '' ? path.join(process.cwd(), hbsDir) : path.join(__dirname, `../../templates/${template}`)
|
|
28
35
|
|
|
29
36
|
const compilerPath = path.join(__dirname, `./${template}-compiler.js`)
|
|
30
37
|
if (!fs.existsSync(compilerPath)) {
|
|
31
38
|
console.error(chalk.red(language(`❌ 暂不支持 [${template}] 框架。欢迎提交 Pull Request 贡献。`, `❌ [${template}] framework not supported. Welcome to contribute a Pull Request to help.`)))
|
|
32
39
|
return
|
|
33
40
|
}
|
|
34
|
-
const { index, resource } = require(compilerPath)
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
const partialsDir = config.hbsDir !== ''
|
|
38
|
-
? path.join(process.cwd(), config.hbsDir, 'handlebars')
|
|
39
|
-
: path.join(__dirname, `../../templates/${template}/handlebars`)
|
|
42
|
+
const partialsDir = hbsDir !== '' ? path.join(process.cwd(), hbsDir, 'handlebars') : path.join(__dirname, `../../templates/${template}/handlebars`)
|
|
40
43
|
fs.readdirSync(partialsDir).forEach(file => {
|
|
41
44
|
if (file.endsWith('.hbs')) {
|
|
42
45
|
const name = path.basename(file, '.hbs') // 去掉后缀拿名字
|
|
@@ -45,62 +48,46 @@ module.exports = {
|
|
|
45
48
|
}
|
|
46
49
|
})
|
|
47
50
|
|
|
48
|
-
const cliCtx = {
|
|
49
|
-
options,
|
|
50
|
-
template,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const llmCtx = {
|
|
54
|
-
apiLinker,
|
|
55
|
-
generateMock,
|
|
56
|
-
recognizePage,
|
|
57
|
-
alignResponseFields
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const utilsCtx = {
|
|
61
|
-
menus,
|
|
62
|
-
config,
|
|
63
|
-
language,
|
|
64
|
-
unwrapSignal,
|
|
65
|
-
isQuerySignal,
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const handlerCtx = {
|
|
69
|
-
apiHandler,
|
|
70
|
-
pageHandler,
|
|
71
|
-
partHandler
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const compileCtx = {
|
|
75
|
-
index,
|
|
76
|
-
resource
|
|
77
|
-
}
|
|
78
|
-
|
|
79
51
|
const promptCtx = {
|
|
52
|
+
mockPrompt: require(`../prompts/mock.js`),
|
|
53
|
+
sysPrompt: require(`../prompts/system.js`),
|
|
54
|
+
apiPrompt: require(`../prompts/${template}/watch-api.js`),
|
|
80
55
|
pagePrompt: require(`../prompts/${template}/watch-page.js`),
|
|
81
56
|
partPrompt: require(`../prompts/${template}/watch-part.js`),
|
|
57
|
+
linkerPrompt: require(`../prompts/${template}/api-linker.js`),
|
|
82
58
|
}
|
|
83
59
|
|
|
84
|
-
const
|
|
60
|
+
const hbsTplCtx = {
|
|
85
61
|
indexTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'index.hbs'), 'utf-8')),
|
|
86
62
|
resourceTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'resource.hbs'), 'utf-8')),
|
|
87
63
|
}
|
|
88
64
|
|
|
65
|
+
const pkgEnv = path.resolve(__dirname, '../.env')
|
|
66
|
+
const localEnv = path.resolve(process.cwd(), '.env')
|
|
67
|
+
require('dotenv').config({ path: fs.existsSync(localEnv) ? localEnv : pkgEnv })
|
|
68
|
+
const openAI = new OpenAI({ apiKey: process.env.API_KEY, baseURL: process.env.BASE_URL })
|
|
69
|
+
|
|
70
|
+
const cliCtx = { options }
|
|
71
|
+
const handlerCtx = { apiHandler, pageHandler, partHandler }
|
|
72
|
+
const finalInfrastructureCtx = { menus, config, ...infrastructureCtx }
|
|
73
|
+
const llmCtx = require('../services/llm')({ config, openAI, template, ...promptCtx })
|
|
74
|
+
const compileCtx = require(compilerPath)({ config, contextStringify, ...coreCtx, ...hbsTplCtx })
|
|
89
75
|
|
|
90
76
|
instance = {
|
|
77
|
+
openAI,
|
|
78
|
+
...uxCtx,
|
|
91
79
|
...cliCtx,
|
|
92
80
|
...llmCtx,
|
|
93
|
-
...
|
|
81
|
+
...coreCtx,
|
|
94
82
|
...promptCtx,
|
|
83
|
+
...hbsTplCtx,
|
|
95
84
|
...handlerCtx,
|
|
96
85
|
...compileCtx,
|
|
97
|
-
|
|
86
|
+
contextStringify,
|
|
87
|
+
...finalInfrastructureCtx,
|
|
98
88
|
}
|
|
99
89
|
return instance
|
|
100
90
|
},
|
|
101
91
|
|
|
102
|
-
/**
|
|
103
|
-
* @description 全频道信号接入:获取全局上下文
|
|
104
|
-
*/
|
|
105
92
|
get: () => instance
|
|
106
93
|
}
|
|
@@ -1,98 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
const { cleanCode, generateSmartImports, formatFormItemAndColumns } = require('../utils/utils.js')
|
|
1
|
+
module.exports = ({ config, contextStringify, indexTpl, resourceTpl, formatFormItemAndColumns, cleanCode, generateSmartImports }) => {
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
* 生成 resource.js 文件(表格列配置、表单配置、字典等)
|
|
6
|
-
* @param {Object} param0 - 函数参数
|
|
7
|
-
* @param {Object} param0.pageConfig - 页面配置对象(包含 tabs、formItems、table 等)
|
|
8
|
-
* @param {Object} param0.resourceTpl - Handlebars 模板函数
|
|
9
|
-
* @returns {string} 生成的 resource.js 代码
|
|
10
|
-
*/
|
|
11
|
-
const resource = ({ pageConfig, resourceTpl }) => {
|
|
3
|
+
const { needMock, responseSuccess } = config
|
|
12
4
|
|
|
13
|
-
|
|
5
|
+
return {
|
|
6
|
+
index: ({ fileName, pageConfig }) => {
|
|
7
|
+
const hasTabs = pageConfig.tabs?.length > 0
|
|
8
|
+
const hasPagination = pageConfig.table.pagination
|
|
9
|
+
const hasFormItems = pageConfig.formItems?.length > 0
|
|
10
|
+
const hasOperate = pageConfig.table?.operation?.length > 0
|
|
11
|
+
const hasImageColumn = pageConfig.table?.columns?.some(item => item.type === 'image')
|
|
12
|
+
const functionButtons = pageConfig.functionButton?.filter(item => !['查询', '重置', 'query', 'search', 'reset'].includes(item.btn.toLowerCase().replaceAll(' ', ''))) || []
|
|
13
|
+
const needRenderAction = hasImageColumn
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
const hasFormItems = pageConfig.formItems?.length > 0
|
|
17
|
-
const tabKeys = pageConfig.tabs.map(tab => tab.key).sort((a, b) => a.length - b.length)
|
|
18
|
-
const optionDict = pageConfig.optionList?.reduce((acc, item) => ({ ...acc, [item.name]: item.options }), {})
|
|
15
|
+
const pageStruct = ['stateBlock', 'handleBlock', 'hookBlock', hasOperate ? 'operateBlock' : '', 'renderBlock'].filter(Boolean)
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
let columnsValue = hasTabs ? 'columns[activeKey]' : 'columns'
|
|
18
|
+
if (hasOperate) {
|
|
19
|
+
columnsValue = `${columnsValue}.concat(operate)`
|
|
20
|
+
}
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
columnsData,
|
|
28
|
-
hasFormItems,
|
|
29
|
-
tabs: pageConfig.tabs,
|
|
30
|
-
dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
|
|
31
|
-
tabColumns: stringify.default(Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_commonColumns_CODE_'])), { indent: 4, maxLength: 100 }),
|
|
32
|
-
formItemsData: !hasTabs ?
|
|
33
|
-
`export const formItems = ${stringify.default(formItems, { indent: 4, maxLength: 120 })}` :
|
|
34
|
-
`const searchItems = ${stringify.default(formItems, { indent: 4, maxLength: 120 })}\n\nexport const formItems = ${stringify.default(Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_searchItems_CODE_'])), { indent: 4, maxLength: 100 })}`,
|
|
35
|
-
}
|
|
22
|
+
const imgAction = Object.fromEntries(pageConfig.table?.columns?.filter(item => item.type === 'image')?.map(item => [item.dataIndex, `_CODE_(_, record) => <a onClick={() => showImg(record, '${item.dataIndex}')}>查看图片</a>_CODE_`]))
|
|
23
|
+
const renderAction = `{${contextStringify({ context: imgAction, maxLength: 120 })}}`.replace(/\n/g, '\n ')
|
|
36
24
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
const viewData = {
|
|
26
|
+
hasTabs,
|
|
27
|
+
pageStruct,
|
|
28
|
+
columnsValue,
|
|
29
|
+
hasFormItems,
|
|
30
|
+
renderAction,
|
|
31
|
+
hasPagination,
|
|
32
|
+
hasImageColumn,
|
|
33
|
+
functionButtons,
|
|
34
|
+
responseSuccess,
|
|
35
|
+
needRenderAction,
|
|
36
|
+
tabs: pageConfig.tabs,
|
|
37
|
+
renderTree: pageConfig.renderTree,
|
|
38
|
+
hasExpandable: pageConfig.table.expandable,
|
|
39
|
+
staticInfoText: pageConfig.staticInfo?.text,
|
|
40
|
+
operations: pageConfig.table.operation || [],
|
|
41
|
+
hasRowSelection: pageConfig.table.rowSelection,
|
|
42
|
+
uri: needMock ? fileName : 'BUNKER_API_ANCHOR_pages',
|
|
43
|
+
formItems: hasFormItems ? (hasTabs ? 'formItems[activeKey]' : 'formItems') : '[]',
|
|
44
|
+
initParams: `{ ${hasTabs ? 'type: tabs[0].key ,' : ''}${hasPagination ? 'pageNo: 1 , pageSize: 10' : ''}}`,
|
|
45
|
+
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* @param {Object} param0.pageConfig - 页面配置对象
|
|
48
|
-
* @returns {string} 生成的 index.js 代码
|
|
49
|
-
*/
|
|
50
|
-
const index = ({ config, fileName, indexTpl, pageConfig }) => {
|
|
47
|
+
const bodyCode = indexTpl(viewData)
|
|
48
|
+
const importsStr = generateSmartImports({ module: 'index', hasTabs, bodyCode, hasFormItems })
|
|
49
|
+
return cleanCode(`${importsStr}\n\n${bodyCode}`)
|
|
50
|
+
},
|
|
51
|
+
resource: ({ pageConfig }) => {
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
const hasPagination = pageConfig.table.pagination
|
|
54
|
-
const hasFormItems = pageConfig.formItems?.length > 0
|
|
55
|
-
const hasOperate = pageConfig.table?.operation?.length > 0
|
|
56
|
-
const hasImageColumn = pageConfig.table?.columns?.some(item => item.type === 'image')
|
|
57
|
-
const renderTree = pageConfig.renderTree?.filter(item => item.toLowerCase() !== 'tabs') || []
|
|
58
|
-
const functionButtons = pageConfig.functionButton?.filter(item => !['查询', '重置', 'query', 'search', 'reset'].includes(item.btn.toLowerCase().replaceAll(' ', ''))) || []
|
|
59
|
-
const needRenderAction = hasImageColumn
|
|
53
|
+
const { formItems, processedColumns, dictBlocks } = formatFormItemAndColumns({ pageConfig })
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
const hasTabs = pageConfig.tabs?.length > 0
|
|
56
|
+
const hasFormItems = pageConfig.formItems?.length > 0
|
|
57
|
+
const tabKeys = pageConfig.tabs.map(tab => tab.key).sort((a, b) => a.length - b.length)
|
|
58
|
+
const optionDict = pageConfig.optionList?.reduce((acc, item) => ({ ...acc, [item.name]: item.options }), {})
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
const columnsData = processedColumns.map(item => {
|
|
61
|
+
delete item.type
|
|
62
|
+
return item
|
|
63
|
+
})
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
const viewData = {
|
|
66
|
+
hasTabs,
|
|
67
|
+
columnsData,
|
|
68
|
+
hasFormItems,
|
|
69
|
+
tabs: pageConfig.tabs,
|
|
70
|
+
dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
|
|
71
|
+
tabColumns: contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_commonColumns_CODE_'])), maxLength: 100 }),
|
|
72
|
+
formItemsData: !hasTabs ?
|
|
73
|
+
`export const formItems = ${contextStringify({ context: formItems, maxLength: 120 })}` :
|
|
74
|
+
`const searchItems = ${contextStringify({ context: formItems, maxLength: 120 })}\n\nexport const formItems = ${contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_searchItems_CODE_'])), maxLength: 100 })}`,
|
|
75
|
+
}
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
columnsValue,
|
|
76
|
-
hasFormItems,
|
|
77
|
-
renderAction,
|
|
78
|
-
hasPagination,
|
|
79
|
-
hasImageColumn,
|
|
80
|
-
functionButtons,
|
|
81
|
-
needRenderAction,
|
|
82
|
-
tabs: pageConfig.tabs,
|
|
83
|
-
responseSuccess: config.responseSuccess,
|
|
84
|
-
hasExpandable: pageConfig.table.expandable,
|
|
85
|
-
staticInfoText: pageConfig.staticInfo?.text,
|
|
86
|
-
operations: pageConfig.table.operation || [],
|
|
87
|
-
hasRowSelection: pageConfig.table.rowSelection,
|
|
88
|
-
uri: config.needMock ? fileName : 'BUNKER_API_ANCHOR_pages',
|
|
89
|
-
formItems: hasFormItems ? (hasTabs ? 'formItems[activeKey]' : 'formItems') : '[]',
|
|
90
|
-
initParams: `{ ${hasTabs ? 'type: tabs[0].key ,' : ''}${hasPagination ? 'pageNo: 1 , pageSize: 10' : ''}}`,
|
|
77
|
+
const bodyCode = resourceTpl(viewData)
|
|
78
|
+
const importsStr = generateSmartImports({ module: 'resource', hasTabs, bodyCode, hasFormItems })
|
|
79
|
+
return cleanCode(`${importsStr}\n\n${bodyCode}`)
|
|
80
|
+
}
|
|
91
81
|
}
|
|
92
|
-
|
|
93
|
-
const bodyCode = indexTpl(viewData)
|
|
94
|
-
const importsStr = generateSmartImports({ module: 'index', hasTabs, bodyCode, hasFormItems })
|
|
95
|
-
return cleanCode(`${importsStr}\n\n${bodyCode}`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = { index, resource }
|
|
82
|
+
}
|
package/src/prompts/mock.js
CHANGED
|
@@ -34,6 +34,7 @@ module.exports = `
|
|
|
34
34
|
### 表格主体 (Table)
|
|
35
35
|
- ⚠️ **操作锁定**: 严禁在 columns 数组中包含“操作”列。
|
|
36
36
|
- **标准项**: {title:'列名', dataIndex:'列名英文名词',type:''}。
|
|
37
|
+
- **注意**: type为text时必须省略type属性。
|
|
37
38
|
- **配置项**: [pagination, expandable, rowSelection] 均为布尔值false,只有页面明确有对应功能时才为true。
|
|
38
39
|
- **标准定义 (Columns)**:
|
|
39
40
|
- enum: 枚举列
|
|
@@ -10,6 +10,7 @@ module.exports = `
|
|
|
10
10
|
## 1. 表格 (Table)
|
|
11
11
|
- 结构: { columns: [{ title: '列名', dataIndex: '列名英文名词', type: '' }] }
|
|
12
12
|
- ⚠️ 字段白名单: [title, dataIndex, sorter, render, filters, onFilter]
|
|
13
|
+
- **注意**: type为text时必须省略type属性。
|
|
13
14
|
- 禁止输出:
|
|
14
15
|
- 严禁在 columns 中包含“操作”列。
|
|
15
16
|
- ***⚠️⚠️⚠️严禁输出formItems,只允许输出columns⚠️⚠️⚠️***
|
|
@@ -1,65 +1,27 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const chalk = require('chalk')
|
|
4
|
-
const { Segment, useDefault } = require('segmentit')
|
|
5
|
-
const segmentit = useDefault(new Segment())
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @function getSemanticKeywords
|
|
9
|
-
* @description [语义精炼厂 2.0] 使用 segmentit 引擎进行物理切片。
|
|
10
|
-
*/
|
|
11
|
-
const getSemanticKeywords = text => {
|
|
12
|
-
// 💡 物理脱水:确保输入为纯净字符串
|
|
13
|
-
const content = Array.isArray(text) ? text.join(' ') : (text || '')
|
|
14
|
-
// 💡 执行分词
|
|
15
|
-
const result = segmentit.doSegment(content, {
|
|
16
|
-
simple: true, // 开启简易模式,提升吞吐效率
|
|
17
|
-
stripPunctuation: true // 物理过滤掉所有的标点符号
|
|
18
|
-
})
|
|
19
|
-
// 💡 提取词条并执行“基因筛选”
|
|
20
|
-
return Array.from(new Set(result.filter(word => word.length >= 2 && !/^[0-9]+$/.test(word))))
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @function getLocalScore
|
|
25
|
-
* @description [战力评估协议] 计算语义重合度。
|
|
26
|
-
*/
|
|
27
|
-
const getLocalScore = (api, pageKeywords, moduleName) => {
|
|
28
|
-
let score = 0
|
|
29
|
-
const path = api.path.toLowerCase()
|
|
30
|
-
const desc = api.desc.toLowerCase()
|
|
31
|
-
const mod = moduleName.toLowerCase()
|
|
32
|
-
|
|
33
|
-
// 💡 权重 A:路径直接包含模块名 (暴击加分 +50)
|
|
34
|
-
if (path.includes(mod)) score += 50
|
|
35
|
-
|
|
36
|
-
// 💡 权重 B:描述包含模块核心词 (中量加分 +10)
|
|
37
|
-
pageKeywords.forEach(word => {
|
|
38
|
-
if (desc.includes(word.toLowerCase())) score += 10
|
|
39
|
-
if (path.includes(word.toLowerCase())) score += 5
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
return score
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @module apiLinker
|
|
47
|
-
* @description [地堡 4.0 核心] 全频道自动寻址协议。
|
|
48
|
-
*/
|
|
49
1
|
module.exports = async () => {
|
|
50
2
|
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
config,
|
|
9
|
+
language,
|
|
10
|
+
apiLinker,
|
|
11
|
+
getLocalScore, getSemanticKeywords,
|
|
12
|
+
} = require('../core/context').get()
|
|
13
|
+
|
|
14
|
+
const { apiDoc, pagesDir } = config
|
|
15
|
+
if (!apiDoc) return
|
|
54
16
|
|
|
55
17
|
console.log(chalk.cyan(language(
|
|
56
18
|
`\n🤖 Pod 153: 启动‘全频道自动寻址协议 [语义扫描版]’...`,
|
|
57
|
-
`\n🤖 Pod 153: Initiating
|
|
19
|
+
`\n🤖 Pod 153: Initiating 'Full-Channel Autonomous Addressing Protocol [Semantic Scan]'...`
|
|
58
20
|
)))
|
|
59
21
|
|
|
60
22
|
try {
|
|
61
23
|
// 1. 抓取情报
|
|
62
|
-
const apiData = await fetch(
|
|
24
|
+
const apiData = await fetch(apiDoc).then(res => res.json())
|
|
63
25
|
const refinedApis = Object.entries(apiData.paths).flatMap(([apiUrl, methods]) => {
|
|
64
26
|
// 💡 适配多方法接口:有的路径下可能既有 GET 也有 POST
|
|
65
27
|
return Object.entries(methods).map(([method, info]) => ({
|
|
@@ -70,12 +32,12 @@ module.exports = async () => {
|
|
|
70
32
|
})
|
|
71
33
|
|
|
72
34
|
// 2. 战场侦察
|
|
73
|
-
const
|
|
74
|
-
const files = fs.readdirSync(
|
|
35
|
+
const pages = path.join(process.cwd(), pagesDir)
|
|
36
|
+
const files = fs.readdirSync(pages)
|
|
75
37
|
|
|
76
38
|
for (const fileName of files) {
|
|
77
|
-
const indexPath = path.join(
|
|
78
|
-
const resourcePath = path.join(
|
|
39
|
+
const indexPath = path.join(pages, fileName, 'index.js')
|
|
40
|
+
const resourcePath = path.join(pages, fileName, 'resource.js')
|
|
79
41
|
|
|
80
42
|
if (fs.existsSync(indexPath) && fs.existsSync(resourcePath)) {
|
|
81
43
|
let indexCode = fs.readFileSync(indexPath, 'utf-8')
|
|
@@ -83,7 +45,7 @@ module.exports = async () => {
|
|
|
83
45
|
// 💡 锁定待通电锚点
|
|
84
46
|
if (indexCode.includes('BUNKER_API_ANCHOR')) {
|
|
85
47
|
const resourceCode = fs.readFileSync(resourcePath, 'utf-8')
|
|
86
|
-
const bunkerAnchors = indexCode.match(/BUNKER_API_ANCHOR_\w+/g)
|
|
48
|
+
const bunkerAnchors = indexCode.match(/BUNKER_API_ANCHOR_\w+/g)?.join('\n') ?? ''
|
|
87
49
|
|
|
88
50
|
// 💡 执行语义提取流程
|
|
89
51
|
const returnMatch = indexCode.match(/return\s*\(([\s\S]*?)\)\s*}/)
|
|
@@ -109,7 +71,7 @@ module.exports = async () => {
|
|
|
109
71
|
)))
|
|
110
72
|
|
|
111
73
|
// 3. 驱动 9S 最终裁决
|
|
112
|
-
const result = await apiLinker(
|
|
74
|
+
const result = await apiLinker({ bunkerAnchors, realApis: finalCandidates })
|
|
113
75
|
|
|
114
76
|
if (result) {
|
|
115
77
|
// 💡 执行物理更替
|
package/src/services/llm.js
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const chalk = require('chalk')
|
|
4
|
-
const { language, getConfig } = require('../utils/utils.js')
|
|
5
|
-
|
|
6
|
-
let client = null
|
|
7
1
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const OpenAI = require('openai')
|
|
11
|
-
const localEnv = path.resolve(process.cwd(), '.env')
|
|
12
|
-
const pkgEnv = path.resolve(__dirname, '../.env')
|
|
13
|
-
require("dotenv").config({
|
|
14
|
-
path: fs.existsSync(localEnv) ? localEnv : pkgEnv
|
|
15
|
-
})
|
|
16
|
-
client = new OpenAI({ apiKey: process.env.API_KEY, baseURL: process.env.BASE_URL })
|
|
17
|
-
}
|
|
18
|
-
return client
|
|
19
|
-
}
|
|
2
|
+
const chalk = require('chalk')
|
|
3
|
+
const { language } = require('../utils/ux')
|
|
20
4
|
|
|
21
|
-
const askAI = async ({ model, messages, response_format = { type: 'json_object' }, retryCount = 0 }) => {
|
|
5
|
+
const askAI = async ({ model, openAI, messages, response_format = { type: 'json_object' }, retryCount = 0 }) => {
|
|
22
6
|
|
|
23
7
|
if (retryCount > 3) {
|
|
24
8
|
throw new Error(language(
|
|
@@ -28,8 +12,7 @@ const askAI = async ({ model, messages, response_format = { type: 'json_object'
|
|
|
28
12
|
}
|
|
29
13
|
|
|
30
14
|
try {
|
|
31
|
-
const
|
|
32
|
-
const response = await openai.chat.completions.create({
|
|
15
|
+
const response = await openAI.chat.completions.create({
|
|
33
16
|
model,
|
|
34
17
|
messages,
|
|
35
18
|
top_p: 0.1,
|
|
@@ -60,66 +43,66 @@ const askAI = async ({ model, messages, response_format = { type: 'json_object'
|
|
|
60
43
|
}
|
|
61
44
|
}
|
|
62
45
|
|
|
63
|
-
module.exports = {
|
|
64
|
-
generateMock: async (columns, fileName) => {
|
|
65
|
-
const config = getConfig()
|
|
66
|
-
const mockPrompt = require('../prompts/mock.js')
|
|
67
|
-
const { MOCK_DESIGNER } = require('../prompts/system.js')
|
|
68
|
-
return askAI({
|
|
69
|
-
model: config.textModel,
|
|
70
|
-
messages: [
|
|
71
|
-
{ role: 'system', content: MOCK_DESIGNER },
|
|
72
|
-
{ role: 'user', content: mockPrompt(columns, fileName) }
|
|
73
|
-
]
|
|
74
|
-
})
|
|
75
|
-
},
|
|
76
|
-
apiLinker: async (options, bunkerAnchors, realApis) => {
|
|
77
|
-
const config = getConfig()
|
|
78
|
-
const { API_DESIGNER } = require('../prompts/system.js')
|
|
79
|
-
const apiPrompt = require(`../prompts/${options.template}/api-linker.js`)
|
|
80
|
-
return askAI({
|
|
81
|
-
model: config.textModel,
|
|
82
|
-
messages: [
|
|
83
|
-
{ role: 'system', content: API_DESIGNER },
|
|
84
|
-
{ role: 'user', content: apiPrompt(bunkerAnchors, realApis) }
|
|
85
|
-
]
|
|
86
|
-
})
|
|
87
|
-
},
|
|
88
|
-
recognizePage: async (prompt, filePath, taskType = 'page') => {
|
|
89
|
-
const config = getConfig()
|
|
90
|
-
const { UI_DESIGNER } = require('../prompts/system.js')
|
|
91
|
-
const sharp = require('sharp')
|
|
92
|
-
const compressedBuffer = await sharp(filePath)
|
|
93
|
-
.resize(1280, null, { withoutEnlargement: true })
|
|
94
|
-
.jpeg({ quality: 80 })
|
|
95
|
-
.toBuffer()
|
|
96
|
-
const base64Image = compressedBuffer.toString('base64')
|
|
46
|
+
module.exports = ({ config, openAI, template, sysPrompt, apiPrompt, mockPrompt, linkerPrompt }) => {
|
|
97
47
|
|
|
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
|
-
}
|
|
48
|
+
const sharp = require('sharp')
|
|
49
|
+
|
|
50
|
+
const { textModel, visionModel } = config
|
|
51
|
+
const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } = sysPrompt
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
generateMock: async ({ columns, fileName }) => {
|
|
55
|
+
return askAI({
|
|
56
|
+
openAI,
|
|
57
|
+
model: textModel,
|
|
58
|
+
messages: [
|
|
59
|
+
{ role: 'system', content: MOCK_DESIGNER },
|
|
60
|
+
{ role: 'user', content: mockPrompt({ columns, fileName }) }
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
},
|
|
64
|
+
apiLinker: async ({ bunkerAnchors, realApis }) => {
|
|
65
|
+
return askAI({
|
|
66
|
+
openAI,
|
|
67
|
+
model: textModel,
|
|
68
|
+
messages: [
|
|
69
|
+
{ role: 'system', content: API_DESIGNER },
|
|
70
|
+
{ role: 'user', content: linkerPrompt({ bunkerAnchors, realApis }) }
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
},
|
|
74
|
+
alignResponseFields: async ({ responseStr, resourceStr }) => {
|
|
75
|
+
return askAI({
|
|
76
|
+
openAI,
|
|
77
|
+
model: textModel,
|
|
78
|
+
messages: [
|
|
79
|
+
{ role: 'system', content: API_DESIGNER },
|
|
80
|
+
{ role: 'user', content: apiPrompt({ responseStr, resourceStr }) }
|
|
81
|
+
]
|
|
82
|
+
})
|
|
83
|
+
},
|
|
84
|
+
recognizePage: async ({ prompt, filePath, taskType = 'page' }) => {
|
|
85
|
+
const compressedBuffer = await sharp(filePath)
|
|
86
|
+
.resize(1280, null, { withoutEnlargement: true })
|
|
87
|
+
.jpeg({ quality: 80 })
|
|
88
|
+
.toBuffer()
|
|
89
|
+
const base64Image = compressedBuffer.toString('base64')
|
|
90
|
+
|
|
91
|
+
return askAI({
|
|
92
|
+
openAI,
|
|
93
|
+
model: visionModel,
|
|
94
|
+
messages: [
|
|
95
|
+
{ role: 'system', content: UI_DESIGNER },
|
|
96
|
+
{
|
|
97
|
+
role: 'user',
|
|
98
|
+
content: [
|
|
99
|
+
{ type: 'text', text: prompt },
|
|
100
|
+
{ type: 'image_url', image_url: { url: `data:image/jpeg;base64,${base64Image}` } }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
response_format: taskType === 'page' ? { type: 'json_schema', strict: true, json_schema: require(`../schema/${template}/page.json`) } : { type: 'json_object' }
|
|
105
|
+
})
|
|
106
|
+
},
|
|
124
107
|
}
|
|
125
108
|
}
|