@yorha2b-lab/autodev 1.0.2 → 1.0.4
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/README.md +3 -2
- package/bin/autodev.js +13 -1
- package/package.json +1 -1
- package/src/commands/watch-api.js +4 -1
- package/src/commands/watch-page.js +2 -2
- package/src/services/llm.js +3 -3
- package/src/utils/utils.js +31 -17
package/README.md
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
基于视觉大模型的前端(Umi+Antd)全自动 CRUD 代码生成器 🚀
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
<video src="https://github.com/user-attachments/assets/6d42fce1-c815-482b-8c6a-4a3b9415ba47.mp4" controls="controls" muted="muted" style="max-width: 100%; display: block; margin: 20px auto;">
|
|
11
|
+
</video>
|
|
11
12
|
|
|
12
13
|
拒绝重复劳动!为什么你需要 Auto CRUD Copilot?
|
|
13
14
|
告别手写 Table/Form:截图即代码,提升你的开发效率,告别烦人的复制粘贴。
|
|
@@ -180,4 +181,4 @@ Auto CRUD Copilot is a **fan-made, non-commercial, open-source tool**.
|
|
|
180
181
|
|
|
181
182
|
**Glory to Mankind.**
|
|
182
183
|
|
|
183
|
-
⭐ 如果这个项目对你有帮助,请给个Star支持一下!
|
|
184
|
+
⭐ 如果这个项目对你有帮助,请给个Star支持一下!
|
package/bin/autodev.js
CHANGED
|
@@ -14,7 +14,7 @@ const localEnv = path.resolve(process.cwd(), '.env')
|
|
|
14
14
|
const pkgEnv = path.resolve(__dirname, '../.env')
|
|
15
15
|
|
|
16
16
|
require("dotenv").config({
|
|
17
|
-
|
|
17
|
+
path: fs.existsSync(localEnv) ? localEnv : pkgEnv
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
const { program } = require('commander')
|
|
@@ -26,6 +26,18 @@ program.version('1.0.0').description('AI驱动的前端CRUD代码生成器')
|
|
|
26
26
|
|
|
27
27
|
program.option('-t, --template <type>', '指定前端框架模板', 'react')
|
|
28
28
|
|
|
29
|
+
program
|
|
30
|
+
.command('init')
|
|
31
|
+
.description('在当前目录初始化 .env 和 config.js 配置文件')
|
|
32
|
+
.action(() => {
|
|
33
|
+
const tplConfig = path.resolve(__dirname, '../config.js')
|
|
34
|
+
const tplEnv = path.resolve(__dirname, '../.env.example')
|
|
35
|
+
fs.copyFileSync(tplConfig, path.join(process.cwd(), 'config.js'))
|
|
36
|
+
fs.copyFileSync(tplEnv, path.join(process.cwd(), '.env'))
|
|
37
|
+
console.log('✅ 已生成 config.js')
|
|
38
|
+
console.log('✅ 已生成 .env')
|
|
39
|
+
})
|
|
40
|
+
|
|
29
41
|
program
|
|
30
42
|
.command('watch:page')
|
|
31
43
|
.description('监听截图,自动生成完整的增删改查页面')
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const chokidar = require('chokidar')
|
|
4
|
-
const
|
|
4
|
+
const { getConfig } = require('../utils/utils.js')
|
|
5
5
|
const { alignSwaggerFields } = require('../services/llm.js')
|
|
6
6
|
|
|
7
7
|
const watchApi = () => {
|
|
8
|
+
|
|
9
|
+
const config = getConfig()
|
|
10
|
+
|
|
8
11
|
const watcher = chokidar.watch('./swagger', {
|
|
9
12
|
persistent: true,
|
|
10
13
|
ignored: /(^|[\/\\])\../,
|
|
@@ -3,15 +3,15 @@ const ora = require('ora')
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const chokidar = require('chokidar')
|
|
5
5
|
const Handlebars = require('handlebars')
|
|
6
|
-
const config = require('../../config.js')
|
|
7
6
|
const pagePrompt = require('../prompts/watch-page.js')
|
|
8
7
|
const { createTaskQueue } = require('../core/task-queue')
|
|
9
8
|
const stringify = require('json-stringify-pretty-compact')
|
|
10
9
|
const { recognizePage, generateMock } = require('../services/llm.js')
|
|
11
|
-
const { copyHooks, copyComponents, getExistingMenus } = require('../utils/utils.js')
|
|
10
|
+
const { getConfig, copyHooks, copyComponents, getExistingMenus } = require('../utils/utils.js')
|
|
12
11
|
|
|
13
12
|
const watchPage = options => {
|
|
14
13
|
|
|
14
|
+
const config = getConfig()
|
|
15
15
|
const compilerPath = path.join(__dirname, `../core/${options.template}-compiler.js`)
|
|
16
16
|
|
|
17
17
|
if (!fs.existsSync(compilerPath)) {
|
package/src/services/llm.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const JSON5 = require('json5')
|
|
2
2
|
const sharp = require('sharp')
|
|
3
|
-
const OpenAI = require('openai')
|
|
4
|
-
const config = require('../../config.js')
|
|
5
3
|
const mockPrompt = require('../prompts/mock.js')
|
|
6
4
|
const apiPrompt = require('../prompts/watch-api.js')
|
|
5
|
+
const { getConfig, initOpenAI } = require('../utils/utils.js')
|
|
7
6
|
const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } = require('../prompts/system.js')
|
|
8
7
|
|
|
9
|
-
const
|
|
8
|
+
const config = getConfig()
|
|
9
|
+
const openai = initOpenAI()
|
|
10
10
|
|
|
11
11
|
const askAI = async (model, messages, retryCount = 0) => {
|
|
12
12
|
|
package/src/utils/utils.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
const
|
|
3
|
+
const OpenAI = require('openai')
|
|
4
4
|
|
|
5
|
+
const getConfig = () => {
|
|
6
|
+
const localConfigPath = path.join(process.cwd(), 'config.js')
|
|
7
|
+
const defaultConfigPath = path.resolve(__dirname, '../../config.js')
|
|
8
|
+
let config = require(defaultConfigPath)
|
|
9
|
+
if (fs.existsSync(localConfigPath)) {
|
|
10
|
+
const userConfig = require(localConfigPath)
|
|
11
|
+
config = { ...config, ...userConfig }
|
|
12
|
+
}
|
|
13
|
+
return config
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const initOpenAI = () => {
|
|
17
|
+
return new OpenAI({ apiKey: process.env.API_KEY, baseURL: process.env.BASE_URL })
|
|
18
|
+
}
|
|
5
19
|
|
|
6
20
|
/**
|
|
7
21
|
* 大模型输出的标准 JSON 无法携带 render: (text) => <Tag> 等箭头函数。
|
|
@@ -20,21 +34,7 @@ const cleanCode = str => {
|
|
|
20
34
|
.trim() + '\n'
|
|
21
35
|
}
|
|
22
36
|
|
|
23
|
-
const
|
|
24
|
-
const targetDir = path.join(process.cwd(), config.hooksDir)
|
|
25
|
-
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
26
|
-
const hookDir = path.join(__dirname, `../../templates/${options.template}/hooks`)
|
|
27
|
-
fs.readdirSync(hookDir).forEach(file => fs.copyFileSync(path.join(hookDir, file), path.join(targetDir, file)))
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const copyComponents = options => {
|
|
31
|
-
const targetDir = path.join(process.cwd(), config.componentsDir)
|
|
32
|
-
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
33
|
-
const componentsDir = path.join(__dirname, `../../templates/${options.template}/components`)
|
|
34
|
-
fs.readdirSync(componentsDir).forEach(file => fs.copyFileSync(path.join(componentsDir, file), path.join(targetDir, file)))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const getExistingMenus = (dir = config.pagesDir) => {
|
|
37
|
+
const getExistingMenus = (dir = 'src/pages') => {
|
|
38
38
|
const pagesDir = path.join(process.cwd(), dir)
|
|
39
39
|
if (!fs.existsSync(pagesDir)) return []
|
|
40
40
|
return fs.readdirSync(pagesDir)
|
|
@@ -66,4 +66,18 @@ const generateSmartImports = (codeStr, hasTabs) => {
|
|
|
66
66
|
return imports.filter(Boolean).join('\n')
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
const copyHooks = (options, hooksDir = 'src/hooks') => {
|
|
70
|
+
const targetDir = path.join(process.cwd(), hooksDir)
|
|
71
|
+
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
72
|
+
const hookDir = path.join(__dirname, `../../templates/${options.template}/hooks`)
|
|
73
|
+
fs.readdirSync(hookDir).forEach(file => fs.copyFileSync(path.join(hookDir, file), path.join(targetDir, file)))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const copyComponents = (options, componentsDir = 'src/components') => {
|
|
77
|
+
const targetDir = path.join(process.cwd(), componentsDir)
|
|
78
|
+
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
79
|
+
const componentsDirectory = path.join(__dirname, `../../templates/${options.template}/components`)
|
|
80
|
+
fs.readdirSync(componentsDirectory).forEach(file => fs.copyFileSync(path.join(componentsDirectory, file), path.join(targetDir, file)))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { getConfig, copyHooks, cleanCode, initOpenAI, copyComponents, getExistingMenus, generateSmartImports }
|