@opensumi/ide-ai-native 2.26.9-rc-1695091570.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/LICENSE +21 -0
- package/lib/browser/ai-chat.contribution.d.ts +26 -0
- package/lib/browser/ai-chat.contribution.d.ts.map +1 -0
- package/lib/browser/ai-chat.contribution.js +227 -0
- package/lib/browser/ai-chat.contribution.js.map +1 -0
- package/lib/browser/ai-chat.module.less +174 -0
- package/lib/browser/ai-chat.service.d.ts +30 -0
- package/lib/browser/ai-chat.service.d.ts.map +1 -0
- package/lib/browser/ai-chat.service.js +134 -0
- package/lib/browser/ai-chat.service.js.map +1 -0
- package/lib/browser/ai-chat.view.d.ts +4 -0
- package/lib/browser/ai-chat.view.d.ts.map +1 -0
- package/lib/browser/ai-chat.view.js +305 -0
- package/lib/browser/ai-chat.view.js.map +1 -0
- package/lib/browser/ai-editor.contribution.d.ts +24 -0
- package/lib/browser/ai-editor.contribution.d.ts.map +1 -0
- package/lib/browser/ai-editor.contribution.js +419 -0
- package/lib/browser/ai-editor.contribution.js.map +1 -0
- package/lib/browser/ai-project/generate.service.d.ts +31 -0
- package/lib/browser/ai-project/generate.service.d.ts.map +1 -0
- package/lib/browser/ai-project/generate.service.js +453 -0
- package/lib/browser/ai-project/generate.service.js.map +1 -0
- package/lib/browser/ai-sumi/sumi.service.d.ts +11 -0
- package/lib/browser/ai-sumi/sumi.service.d.ts.map +1 -0
- package/lib/browser/ai-sumi/sumi.service.js +64 -0
- package/lib/browser/ai-sumi/sumi.service.js.map +1 -0
- package/lib/browser/code-widget/ai-code-document.provider.d.ts +10 -0
- package/lib/browser/code-widget/ai-code-document.provider.d.ts.map +1 -0
- package/lib/browser/code-widget/ai-code-document.provider.js +26 -0
- package/lib/browser/code-widget/ai-code-document.provider.js.map +1 -0
- package/lib/browser/code-widget/ai-code-widget.d.ts +20 -0
- package/lib/browser/code-widget/ai-code-widget.d.ts.map +1 -0
- package/lib/browser/code-widget/ai-code-widget.js +164 -0
- package/lib/browser/code-widget/ai-code-widget.js.map +1 -0
- package/lib/browser/components/AIImprove.d.ts +9 -0
- package/lib/browser/components/AIImprove.d.ts.map +1 -0
- package/lib/browser/components/AIImprove.js +34 -0
- package/lib/browser/components/AIImprove.js.map +1 -0
- package/lib/browser/components/AIInput.d.ts +5 -0
- package/lib/browser/components/AIInput.d.ts.map +1 -0
- package/lib/browser/components/AIInput.js +21 -0
- package/lib/browser/components/AIInput.js.map +1 -0
- package/lib/browser/components/ChatEditor.d.ts +5 -0
- package/lib/browser/components/ChatEditor.d.ts.map +1 -0
- package/lib/browser/components/ChatEditor.js +85 -0
- package/lib/browser/components/ChatEditor.js.map +1 -0
- package/lib/browser/components/ChatInput.d.ts +6 -0
- package/lib/browser/components/ChatInput.d.ts.map +1 -0
- package/lib/browser/components/ChatInput.js +127 -0
- package/lib/browser/components/ChatInput.js.map +1 -0
- package/lib/browser/components/ChatMoreActions.d.ts +5 -0
- package/lib/browser/components/ChatMoreActions.d.ts.map +1 -0
- package/lib/browser/components/ChatMoreActions.js +26 -0
- package/lib/browser/components/ChatMoreActions.js.map +1 -0
- package/lib/browser/components/Thinking.d.ts +3 -0
- package/lib/browser/components/Thinking.d.ts.map +1 -0
- package/lib/browser/components/Thinking.js +19 -0
- package/lib/browser/components/Thinking.js.map +1 -0
- package/lib/browser/components/components.module.less +259 -0
- package/lib/browser/components/lineVertical.d.ts +4 -0
- package/lib/browser/components/lineVertical.d.ts.map +1 -0
- package/lib/browser/components/lineVertical.js +22 -0
- package/lib/browser/components/lineVertical.js.map +1 -0
- package/lib/browser/content-widget/ai-content-widget.d.ts +38 -0
- package/lib/browser/content-widget/ai-content-widget.d.ts.map +1 -0
- package/lib/browser/content-widget/ai-content-widget.js +97 -0
- package/lib/browser/content-widget/ai-content-widget.js.map +1 -0
- package/lib/browser/content-widget/ai-inline-chat-panel.d.ts +6 -0
- package/lib/browser/content-widget/ai-inline-chat-panel.d.ts.map +1 -0
- package/lib/browser/content-widget/ai-inline-chat-panel.js +108 -0
- package/lib/browser/content-widget/ai-inline-chat-panel.js.map +1 -0
- package/lib/browser/content-widget/ai-inline-chat.module.less +74 -0
- package/lib/browser/content-widget/ai-inline-chat.service.d.ts +23 -0
- package/lib/browser/content-widget/ai-inline-chat.service.d.ts.map +1 -0
- package/lib/browser/content-widget/ai-inline-chat.service.js +47 -0
- package/lib/browser/content-widget/ai-inline-chat.service.js.map +1 -0
- package/lib/browser/diff-widget/ai-diff-document.provider.d.ts +10 -0
- package/lib/browser/diff-widget/ai-diff-document.provider.d.ts.map +1 -0
- package/lib/browser/diff-widget/ai-diff-document.provider.js +26 -0
- package/lib/browser/diff-widget/ai-diff-document.provider.js.map +1 -0
- package/lib/browser/diff-widget/ai-diff-widget.d.ts +20 -0
- package/lib/browser/diff-widget/ai-diff-widget.d.ts.map +1 -0
- package/lib/browser/diff-widget/ai-diff-widget.js +158 -0
- package/lib/browser/diff-widget/ai-diff-widget.js.map +1 -0
- package/lib/browser/index.d.ts +12 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +84 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/inline-completions/constants.d.ts +62 -0
- package/lib/browser/inline-completions/constants.d.ts.map +1 -0
- package/lib/browser/inline-completions/constants.js +69 -0
- package/lib/browser/inline-completions/constants.js.map +1 -0
- package/lib/browser/inline-completions/provider.d.ts +27 -0
- package/lib/browser/inline-completions/provider.d.ts.map +1 -0
- package/lib/browser/inline-completions/provider.js +63 -0
- package/lib/browser/inline-completions/provider.js.map +1 -0
- package/lib/browser/override/ai-editor-tab.service.d.ts +6 -0
- package/lib/browser/override/ai-editor-tab.service.d.ts.map +1 -0
- package/lib/browser/override/ai-editor-tab.service.js +22 -0
- package/lib/browser/override/ai-editor-tab.service.js.map +1 -0
- package/lib/browser/override/ai-marker.service.d.ts +11 -0
- package/lib/browser/override/ai-marker.service.d.ts.map +1 -0
- package/lib/browser/override/ai-marker.service.js +55 -0
- package/lib/browser/override/ai-marker.service.js.map +1 -0
- package/lib/browser/override/global.styles.less +268 -0
- package/lib/browser/override/layout/layout-config.d.ts +6 -0
- package/lib/browser/override/layout/layout-config.d.ts.map +1 -0
- package/lib/browser/override/layout/layout-config.js +17 -0
- package/lib/browser/override/layout/layout-config.js.map +1 -0
- package/lib/browser/override/layout/layout.module.less +7 -0
- package/lib/browser/override/layout/main-slot-renderer.d.ts +4 -0
- package/lib/browser/override/layout/main-slot-renderer.d.ts.map +1 -0
- package/lib/browser/override/layout/main-slot-renderer.js +22 -0
- package/lib/browser/override/layout/main-slot-renderer.js.map +1 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.contribution.d.ts +8 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.contribution.d.ts.map +1 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.contribution.js +32 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.contribution.js.map +1 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.module.less +41 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.view.d.ts +3 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.view.d.ts.map +1 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.view.js +62 -0
- package/lib/browser/override/layout/menu-bar/menu-bar.view.js.map +1 -0
- package/lib/browser/override/layout/tabbar.view.d.ts +17 -0
- package/lib/browser/override/layout/tabbar.view.d.ts.map +1 -0
- package/lib/browser/override/layout/tabbar.view.js +38 -0
- package/lib/browser/override/layout/tabbar.view.js.map +1 -0
- package/lib/browser/override/override.module.less +32 -0
- package/lib/browser/override/theme/default-theme.d.ts +315 -0
- package/lib/browser/override/theme/default-theme.d.ts.map +1 -0
- package/lib/browser/override/theme/default-theme.js +821 -0
- package/lib/browser/override/theme/default-theme.js.map +1 -0
- package/lib/browser/run/run.service.d.ts +52 -0
- package/lib/browser/run/run.service.d.ts.map +1 -0
- package/lib/browser/run/run.service.js +176 -0
- package/lib/browser/run/run.service.js.map +1 -0
- package/lib/common/command.d.ts +17 -0
- package/lib/common/command.d.ts.map +1 -0
- package/lib/common/command.js +21 -0
- package/lib/common/command.js.map +1 -0
- package/lib/common/index.d.ts +37 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +22 -0
- package/lib/common/index.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -0
- package/lib/node/index.d.ts +10 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +32 -0
- package/lib/node/index.js.map +1 -0
- package/package.json +38 -0
- package/src/browser/ai-chat.contribution.ts +294 -0
- package/src/browser/ai-chat.module.less +174 -0
- package/src/browser/ai-chat.service.ts +152 -0
- package/src/browser/ai-chat.view.tsx +421 -0
- package/src/browser/ai-editor.contribution.ts +521 -0
- package/src/browser/ai-project/generate.service.ts +505 -0
- package/src/browser/ai-sumi/sumi.service.ts +65 -0
- package/src/browser/code-widget/ai-code-document.provider.ts +22 -0
- package/src/browser/code-widget/ai-code-widget.tsx +202 -0
- package/src/browser/components/AIImprove.tsx +45 -0
- package/src/browser/components/AIInput.tsx +30 -0
- package/src/browser/components/ChatEditor.tsx +129 -0
- package/src/browser/components/ChatInput.tsx +197 -0
- package/src/browser/components/ChatMoreActions.tsx +33 -0
- package/src/browser/components/Thinking.tsx +23 -0
- package/src/browser/components/components.module.less +259 -0
- package/src/browser/components/lineVertical.tsx +19 -0
- package/src/browser/content-widget/ai-content-widget.tsx +132 -0
- package/src/browser/content-widget/ai-inline-chat-panel.tsx +154 -0
- package/src/browser/content-widget/ai-inline-chat.module.less +74 -0
- package/src/browser/content-widget/ai-inline-chat.service.ts +46 -0
- package/src/browser/diff-widget/ai-diff-document.provider.ts +22 -0
- package/src/browser/diff-widget/ai-diff-widget.tsx +196 -0
- package/src/browser/index.ts +91 -0
- package/src/browser/inline-completions/constants.ts +108 -0
- package/src/browser/inline-completions/provider.ts +55 -0
- package/src/browser/override/ai-editor-tab.service.tsx +22 -0
- package/src/browser/override/ai-marker.service.tsx +55 -0
- package/src/browser/override/global.styles.less +268 -0
- package/src/browser/override/layout/layout-config.ts +21 -0
- package/src/browser/override/layout/layout.module.less +7 -0
- package/src/browser/override/layout/main-slot-renderer.tsx +62 -0
- package/src/browser/override/layout/menu-bar/menu-bar.contribution.tsx +28 -0
- package/src/browser/override/layout/menu-bar/menu-bar.module.less +41 -0
- package/src/browser/override/layout/menu-bar/menu-bar.view.tsx +92 -0
- package/src/browser/override/layout/tabbar.view.tsx +99 -0
- package/src/browser/override/override.module.less +32 -0
- package/src/browser/override/theme/default-theme.ts +818 -0
- package/src/browser/run/run.service.ts +183 -0
- package/src/common/command.ts +21 -0
- package/src/common/index.ts +39 -0
- package/src/index.ts +1 -0
- package/src/node/index.ts +24 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Injectable, Autowired } from '@opensumi/di';
|
|
3
|
+
|
|
4
|
+
import { AiGPTBackSerivcePath } from '../../common';
|
|
5
|
+
|
|
6
|
+
const enum FRAMEWORK {
|
|
7
|
+
minifish = 'minifish',
|
|
8
|
+
bigfish = 'bigfish',
|
|
9
|
+
sofa = 'sofa',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Requirements {
|
|
13
|
+
language: string;
|
|
14
|
+
framework: string;
|
|
15
|
+
requirements: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class AiProjectGenerateService {
|
|
20
|
+
@Autowired(AiGPTBackSerivcePath)
|
|
21
|
+
aiBackService: any;
|
|
22
|
+
|
|
23
|
+
private matchFramework(language: string, framework: string) {
|
|
24
|
+
if (/javascript|typescript/i.test(language)) {
|
|
25
|
+
return /minifish/i.test(framework) ? FRAMEWORK.minifish : FRAMEWORK.bigfish;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (/java/i.test(language)) {
|
|
29
|
+
return FRAMEWORK.sofa;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return framework;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public async switchProjectLanguage(input: string) {
|
|
36
|
+
const prompt = `
|
|
37
|
+
### 介绍 ###
|
|
38
|
+
我会提供一份关于编程项目的描述,请基于项目描述提取出项目所使用的编程语言、适合的编程框架,以及分析一下项目的具体需求。
|
|
39
|
+
如果是支付宝小程序相关的需求,编程语言为 Javascript,编程框架使用: Minifish
|
|
40
|
+
如果是与前端有关的需求,编程语言为 Typescript,编程框架请使用: Bigfish
|
|
41
|
+
下面是一个问答示例,请参照示例的格式,给出回答。
|
|
42
|
+
|
|
43
|
+
### 示例 ###
|
|
44
|
+
示例提问:创建一个 java 项目,与营销相关
|
|
45
|
+
示例回答:
|
|
46
|
+
编程语言: JAVA
|
|
47
|
+
编程框架: Sofa Boot、Sofa4
|
|
48
|
+
项目需求:创建一个用于营销的项目
|
|
49
|
+
|
|
50
|
+
### 需求 ###
|
|
51
|
+
我的问题: ${input}
|
|
52
|
+
`;
|
|
53
|
+
const res = await this.aiBackService.aiAntGlm(prompt);
|
|
54
|
+
console.log('gen request res: ', res);
|
|
55
|
+
const reg =
|
|
56
|
+
/(编程语言)(:|:)?\s?(?<language>.*)\n*\s*(编程框架)(:|:)?\s?(?<framework>.*)\n*\s*(项目需求)(:|:)?\s?(?<requirements>.*)/i;
|
|
57
|
+
const match = reg.exec(res.data);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
match &&
|
|
61
|
+
({
|
|
62
|
+
...(match.groups || {}),
|
|
63
|
+
framework: match.groups?.framework.split('、'),
|
|
64
|
+
} as { language: string; framework: string[]; requirements: string })
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private generateStructurePrompt({ language, framework }: Requirements) {
|
|
69
|
+
switch (this.matchFramework(language, framework)) {
|
|
70
|
+
case FRAMEWORK.minifish:
|
|
71
|
+
return `
|
|
72
|
+
├──mini.project.json
|
|
73
|
+
├──app.js
|
|
74
|
+
├──app.json
|
|
75
|
+
├──README.md
|
|
76
|
+
├──.gitignore
|
|
77
|
+
└──pages
|
|
78
|
+
├──order
|
|
79
|
+
│ ├──index.js
|
|
80
|
+
│ ├──index.axml
|
|
81
|
+
│ ├──index.acss
|
|
82
|
+
│ └──index.json
|
|
83
|
+
└──detail
|
|
84
|
+
├──index.js
|
|
85
|
+
├──index.axml
|
|
86
|
+
├──index.acss
|
|
87
|
+
└──index.json
|
|
88
|
+
`;
|
|
89
|
+
case FRAMEWORK.bigfish:
|
|
90
|
+
return `
|
|
91
|
+
├──package.json
|
|
92
|
+
├──app.tsx
|
|
93
|
+
├──README.md
|
|
94
|
+
├──.gitignore
|
|
95
|
+
├──.eslintrc
|
|
96
|
+
├──src
|
|
97
|
+
│ └──pages
|
|
98
|
+
│ └──order
|
|
99
|
+
│ ├──index.tsx
|
|
100
|
+
│ └──index.less
|
|
101
|
+
└──config
|
|
102
|
+
├──config.ts
|
|
103
|
+
└──router.config.ts
|
|
104
|
+
`;
|
|
105
|
+
default:
|
|
106
|
+
return `
|
|
107
|
+
├──.gitignore
|
|
108
|
+
├──pom.xml
|
|
109
|
+
├──README.md
|
|
110
|
+
└──app
|
|
111
|
+
├──bootstrap
|
|
112
|
+
│ ├──src
|
|
113
|
+
│ │ ├──main
|
|
114
|
+
│ │ │ ├──java
|
|
115
|
+
│ │ │ │ └──com
|
|
116
|
+
│ │ │ │ └──alipay
|
|
117
|
+
│ │ │ │ └──order
|
|
118
|
+
│ │ │ │ └──DemoApplication.java
|
|
119
|
+
│ │ │ └──resources
|
|
120
|
+
│ │ │ └──config
|
|
121
|
+
│ │ │ └──application.properties
|
|
122
|
+
│ │ └──test
|
|
123
|
+
│ │ └──java
|
|
124
|
+
│ │ └──com
|
|
125
|
+
│ │ └──alipay
|
|
126
|
+
│ │ └──order
|
|
127
|
+
│ │ └──DemoApplicationTest.java
|
|
128
|
+
│ └──pom.xml
|
|
129
|
+
├──model
|
|
130
|
+
│ ├──src
|
|
131
|
+
│ │ ├──main
|
|
132
|
+
│ │ │ ├──java
|
|
133
|
+
│ │ │ │ └──com
|
|
134
|
+
│ │ │ │ └──alipay
|
|
135
|
+
│ │ │ │ └──order
|
|
136
|
+
│ │ │ │ └──model
|
|
137
|
+
│ │ └──test
|
|
138
|
+
│ │ └──java
|
|
139
|
+
│ │ └──com
|
|
140
|
+
│ │ └──alipay
|
|
141
|
+
│ │ └──order
|
|
142
|
+
│ │ └──model
|
|
143
|
+
│ └──pom.xml
|
|
144
|
+
├──service
|
|
145
|
+
│ ├──src
|
|
146
|
+
│ │ ├──main
|
|
147
|
+
│ │ │ ├──java
|
|
148
|
+
│ │ │ │ └──com
|
|
149
|
+
│ │ │ │ └──alipay
|
|
150
|
+
│ │ │ │ └──order
|
|
151
|
+
│ │ │ │ └──service
|
|
152
|
+
│ │ └──test
|
|
153
|
+
│ │ └──java
|
|
154
|
+
│ │ └──com
|
|
155
|
+
│ │ └──alipay
|
|
156
|
+
│ │ └──order
|
|
157
|
+
│ │ └──service
|
|
158
|
+
│ └──pom.xml
|
|
159
|
+
└──utils
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
codeStructure: string;
|
|
165
|
+
|
|
166
|
+
public async generateProjectStructure(projectInfo: Requirements) {
|
|
167
|
+
const { language, framework, requirements } = projectInfo;
|
|
168
|
+
const prompt = `
|
|
169
|
+
我会提供一份项目的需求,包含使用的编程语言、编程框架、以及项目的具体需求,请结合具体需求,给出代码目录结构。只给出关键的文件以及文件路径即可。
|
|
170
|
+
|
|
171
|
+
示例提问:使用 ${language} 的 ${framework} 框架,创建一个关于订单的项目
|
|
172
|
+
示例回答:\`\`\`${this.generateStructurePrompt(projectInfo)}\`\`\`
|
|
173
|
+
|
|
174
|
+
(请参照示例回答,根据需求按照回答格式返回答案)
|
|
175
|
+
我的问题:${requirements}
|
|
176
|
+
`;
|
|
177
|
+
const structure = await this.aiBackService.aiCodeLLama(prompt);
|
|
178
|
+
console.log('gen structure res: ', structure);
|
|
179
|
+
|
|
180
|
+
const structureCode = /```\n?(?<code>[\s\S]*?)```/g.exec(structure);
|
|
181
|
+
console.log('gen structure code: ', structureCode);
|
|
182
|
+
|
|
183
|
+
let flag = false;
|
|
184
|
+
let filePathList: string[] = [];
|
|
185
|
+
if (structureCode) {
|
|
186
|
+
filePathList = this.parseFilePath(structureCode.groups?.code || '');
|
|
187
|
+
const filePathRegex = /^([a-zA-Z0-9\s_-]+[\\/])*[a-zA-Z0-9\s_-]*(\.[a-zA-Z0-9]+)+$/;
|
|
188
|
+
if (filePathList.filter((f) => filePathRegex.test(f)).length === filePathList.length) {
|
|
189
|
+
flag = true;
|
|
190
|
+
this.codeStructure = filePathList.join('\n');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return flag ? filePathList : await this.generateProjectStructure(projectInfo);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private parseFilePath(input: string) {
|
|
198
|
+
const lines = input.split('\n');
|
|
199
|
+
const paths: string[] = [];
|
|
200
|
+
const stack: string[] = [];
|
|
201
|
+
|
|
202
|
+
let lastDepth = 0;
|
|
203
|
+
for (const line of lines) {
|
|
204
|
+
if (!/\w/.test(line)) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const lineWithoutSpace = line.replace(/(├──|└──)\s/g, '$1');
|
|
208
|
+
const match = lineWithoutSpace.match(/(\s)/g);
|
|
209
|
+
const depth = match ? Math.round(match.length / 2) : 0;
|
|
210
|
+
|
|
211
|
+
// 获取文件或目录的名称
|
|
212
|
+
const name = lineWithoutSpace.replace(/(├──|└──|│\s+)/g, '').trim();
|
|
213
|
+
|
|
214
|
+
// 如果当前深度小于栈的深度,从栈中弹出元素
|
|
215
|
+
if (depth < lastDepth) {
|
|
216
|
+
stack.splice(depth);
|
|
217
|
+
}
|
|
218
|
+
lastDepth = depth;
|
|
219
|
+
|
|
220
|
+
while (depth < stack.length) {
|
|
221
|
+
stack.pop();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (lineWithoutSpace.indexOf('.') !== -1) {
|
|
225
|
+
const path = [...stack, name].join('/');
|
|
226
|
+
paths.push(path);
|
|
227
|
+
} else {
|
|
228
|
+
// 如果是目录,将其添加到栈中
|
|
229
|
+
stack.push(name);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return paths.map((path) => path.replace(/^root\//, ''));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public async generateFile(filePathList: string[], projectInfo: Requirements, callback: (path: string) => void) {
|
|
237
|
+
switch (this.matchFramework(projectInfo.language, projectInfo.framework)) {
|
|
238
|
+
case FRAMEWORK.minifish:
|
|
239
|
+
return this.generateMinifishProject(filePathList, projectInfo.requirements, callback);
|
|
240
|
+
case FRAMEWORK.bigfish:
|
|
241
|
+
return this.generateBigfishProject(filePathList, projectInfo, callback);
|
|
242
|
+
default:
|
|
243
|
+
return this.generateCommonProject(filePathList, projectInfo, callback);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private async generateMinifishProject(fileList: string[], requirements: string, callback: (path: string) => void) {
|
|
248
|
+
const singleFileList: string[] = [];
|
|
249
|
+
const dirMap = new Map<string, string[]>();
|
|
250
|
+
|
|
251
|
+
fileList.forEach((filePath) => {
|
|
252
|
+
const pathArray = filePath.split('/');
|
|
253
|
+
if (pathArray.length > 1) {
|
|
254
|
+
const dir = pathArray.slice(0, -1).join('/');
|
|
255
|
+
if (dirMap.get(dir)) {
|
|
256
|
+
dirMap.get(dir)?.push(filePath);
|
|
257
|
+
} else {
|
|
258
|
+
dirMap.set(dir, [filePath]);
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
singleFileList.push(filePath);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
await Promise.all(
|
|
266
|
+
singleFileList.map(async (path) => {
|
|
267
|
+
callback(path);
|
|
268
|
+
await this.generateMinifishSingleFile(path, requirements);
|
|
269
|
+
}),
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
for (const dir of dirMap.values()) {
|
|
273
|
+
dir.forEach((path) => callback(path));
|
|
274
|
+
await this.generateMinifishDirFile(dir, requirements);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private pointPrompt = `
|
|
279
|
+
生成的代码需要注意以下几点:
|
|
280
|
+
1. 生成的代码需要使用 Markdown 的代码块的语法。例如: \`\`\` // code \`\`\`。
|
|
281
|
+
2. 支付宝小程序的 axml 语法是 a:xxx 不是 wx:xxx。例如:a:if
|
|
282
|
+
3. axml文件时间绑定语法请使用 onEvent。例如:onTap、onInput
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
private requirementPrompt = (requirements: string) => `
|
|
286
|
+
项目完整需求如下: ${requirements}
|
|
287
|
+
需求对应的完整的文件目录如下:\`\`\`
|
|
288
|
+
${this.codeStructure}
|
|
289
|
+
\`\`\`
|
|
290
|
+
`;
|
|
291
|
+
|
|
292
|
+
private async generateMinifishSingleFile(filePath: string, requirements: string) {
|
|
293
|
+
const commonFile = ['mini.project.json', 'README.md', '.gitignore'];
|
|
294
|
+
let code;
|
|
295
|
+
if (commonFile.find((f) => f === filePath)) {
|
|
296
|
+
code = template[filePath];
|
|
297
|
+
} else {
|
|
298
|
+
const prompt = `
|
|
299
|
+
基于我提供的项目需求与文件路径,生成对应的代码。我的需求可能需要多个文件才能满足,我会提供完整的目录结构,但每次我只会提供一个文件路径。
|
|
300
|
+
你需要结合我的需求与完整的项目路径,先判断需要生成的文件属于需求中的哪个页面,再生成代码,
|
|
301
|
+
${this.pointPrompt}
|
|
302
|
+
${this.requirementPrompt(requirements)}
|
|
303
|
+
|
|
304
|
+
需要生成的代码文件是: ${filePath}
|
|
305
|
+
`;
|
|
306
|
+
|
|
307
|
+
code = await this.generateFileCode(prompt);
|
|
308
|
+
}
|
|
309
|
+
await this.aiBackService.generateFileByPath(filePath, code || '{}');
|
|
310
|
+
|
|
311
|
+
return code;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private async generateMinifishDirFile(filePathList: string[], requirements: string) {
|
|
315
|
+
const axmlFile = filePathList.find((path) => path.endsWith('.axml'));
|
|
316
|
+
if (axmlFile) {
|
|
317
|
+
const axmlCode = await this.generateMinifishSingleFile(axmlFile, requirements);
|
|
318
|
+
const otherFile = filePathList.filter((path) => path !== axmlFile);
|
|
319
|
+
await Promise.all(
|
|
320
|
+
otherFile.map(async (path) => {
|
|
321
|
+
const prompt = `
|
|
322
|
+
我会给出项目的需求,需求可能需要多个页面才能实现,我会提供完整的项目路径,以及其中单个页面的 axml 文件代码。
|
|
323
|
+
请帮我基于需要生成的文件路径,先判断属于需求中的哪个页面的文件,再判断文件类型,根据 axml 文件代码,生成对应的 js、acss、json 文件的代码。
|
|
324
|
+
${this.pointPrompt}
|
|
325
|
+
${this.requirementPrompt(requirements)}
|
|
326
|
+
|
|
327
|
+
已有的axml文件路径为: ${axmlFile}
|
|
328
|
+
已有的axml文件代码为:\`\`\`
|
|
329
|
+
${axmlCode}
|
|
330
|
+
\`\`\`
|
|
331
|
+
|
|
332
|
+
需要生成代码文件为:${path}
|
|
333
|
+
`;
|
|
334
|
+
const code = await this.generateFileCode(prompt);
|
|
335
|
+
await this.aiBackService.generateFileByPath(path, code || '{}');
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
} else {
|
|
339
|
+
await Promise.all(filePathList.map((path) => this.generateMinifishSingleFile(path, requirements)));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private async generateBigfishProject(
|
|
344
|
+
fileList: string[],
|
|
345
|
+
projectInfo: Requirements,
|
|
346
|
+
callback: (path: string) => void,
|
|
347
|
+
) {
|
|
348
|
+
const templateFile = ['package.json'];
|
|
349
|
+
while (fileList.length) {
|
|
350
|
+
const part = fileList.splice(0, 1);
|
|
351
|
+
await Promise.all(
|
|
352
|
+
part.map(async (file) => {
|
|
353
|
+
callback(file);
|
|
354
|
+
if (templateFile.find((f) => f === file)) {
|
|
355
|
+
await this.aiBackService.generateFileByPath(file, template[file]);
|
|
356
|
+
} else {
|
|
357
|
+
await this.generateBigfishFile(file, projectInfo);
|
|
358
|
+
}
|
|
359
|
+
}),
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private async generateBigfishFile(filePath: string, projectInfo: Requirements) {
|
|
365
|
+
const { requirements, language } = projectInfo;
|
|
366
|
+
const prompt = `
|
|
367
|
+
Generate corresponding code based on the project requirements and file path I provided. My requirements may require multiple files to fulfill, and I will provide the complete directory structure, but each time I will only provide one file path.
|
|
368
|
+
You need to combine my requirements with the complete project path, first determine which page the file to be generated belongs to in the requirements, and then generate the code.
|
|
369
|
+
The project uses front-end technologies such as ${language} and less, and framework is Bigfish with React, the generated code should comply with the corresponding file type.
|
|
370
|
+
(The Bigfish framework is an extension of umi.js. The file content can refer to umi.js, but if some function import from umi, it needs to be replaced to bigfish.)
|
|
371
|
+
Project requirements is: ${requirements}
|
|
372
|
+
Project dir strucutre is:\`\`\`
|
|
373
|
+
${this.codeStructure}
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
(The generated code needs to be wrapped in Markdown code block syntax and just reply code only)
|
|
377
|
+
The code need generate is: ${filePath}`;
|
|
378
|
+
|
|
379
|
+
const code = await this.generateFileCode(prompt);
|
|
380
|
+
await this.aiBackService.generateFileByPath(filePath, code || '');
|
|
381
|
+
|
|
382
|
+
return code;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private async generateCommonProject(fileList: string[], projectInfo: Requirements, callback: (path: string) => void) {
|
|
386
|
+
while (fileList.length) {
|
|
387
|
+
const part = fileList.splice(0, 1);
|
|
388
|
+
await Promise.all(
|
|
389
|
+
part.map(async (file) => {
|
|
390
|
+
callback(file);
|
|
391
|
+
await this.generateCommonFile(file, projectInfo);
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private async generateCommonFile(filePath: string, projectInfo: Requirements) {
|
|
398
|
+
const { requirements, language, framework } = projectInfo;
|
|
399
|
+
const prompt = `
|
|
400
|
+
Generate corresponding code based on the project requirements and file path I provided. My requirements may require multiple files to fulfill, and I will provide the complete directory structure, but each time I will only provide one file path.
|
|
401
|
+
You need to combine my requirements with the complete project path, first determine which page the file to be generated belongs to in the requirements, and then generate the code.
|
|
402
|
+
The project uses ${language}, and framework is ${framework}, the generated code should comply with the corresponding file type.
|
|
403
|
+
Project requirements is: ${requirements}
|
|
404
|
+
Project dir strucutre is:\`\`\`
|
|
405
|
+
${this.codeStructure}
|
|
406
|
+
\`\`\`
|
|
407
|
+
|
|
408
|
+
(The generated code needs to be wrapped in Markdown code block syntax and just reply code only)
|
|
409
|
+
The code need generate is: ${filePath}`;
|
|
410
|
+
|
|
411
|
+
const code = await this.generateFileCode(prompt);
|
|
412
|
+
await this.aiBackService.generateFileByPath(filePath, code || '');
|
|
413
|
+
|
|
414
|
+
return code;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
private async generateFileCode(prompt: string) {
|
|
418
|
+
let times = 0;
|
|
419
|
+
let code;
|
|
420
|
+
while (!code && times < 5) {
|
|
421
|
+
const content = await this.aiBackService.aiCodeLLama(prompt);
|
|
422
|
+
console.log('gen file content: ', content);
|
|
423
|
+
const codeMatch = /```\w*\n(\/\/\s.*\n)?(?<code>[\s\S]*?)```/g.exec(content);
|
|
424
|
+
code = codeMatch && codeMatch.groups?.code ? codeMatch.groups?.code : content;
|
|
425
|
+
console.log('gen file code: ', code);
|
|
426
|
+
times++;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return code;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
public async clearWorkspace() {
|
|
433
|
+
await this.aiBackService.clearWorkspace();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const template = {
|
|
438
|
+
'mini.project.json': `
|
|
439
|
+
{
|
|
440
|
+
"enableAppxNg": true
|
|
441
|
+
}
|
|
442
|
+
`,
|
|
443
|
+
'README.md': `
|
|
444
|
+
一个简单的示例 Demo
|
|
445
|
+
`,
|
|
446
|
+
'.gitignore': `
|
|
447
|
+
logs
|
|
448
|
+
node_modules
|
|
449
|
+
npm-debug.log
|
|
450
|
+
dist
|
|
451
|
+
public
|
|
452
|
+
.DS_Store
|
|
453
|
+
.nyc_output
|
|
454
|
+
.basement
|
|
455
|
+
.umi
|
|
456
|
+
.umi-production
|
|
457
|
+
.idea
|
|
458
|
+
.history
|
|
459
|
+
.node
|
|
460
|
+
`,
|
|
461
|
+
'package.json': `
|
|
462
|
+
{
|
|
463
|
+
"name": "new project",
|
|
464
|
+
"version": "1.0.0",
|
|
465
|
+
"private": true,
|
|
466
|
+
"scripts": {
|
|
467
|
+
"build": "bigfish build",
|
|
468
|
+
"ci": "bigfish lint",
|
|
469
|
+
"dev": "bigfish dev",
|
|
470
|
+
"devs": "cross-env MOCK=none bigfish dev",
|
|
471
|
+
"format": "prettier --cache --write .",
|
|
472
|
+
"postinstall": "bigfish setup",
|
|
473
|
+
"lint": "bigfish lint",
|
|
474
|
+
"lint:fix": "bigfish lint --fix",
|
|
475
|
+
"oneapi": "npm run oneapi:service && npm run oneapi:mock",
|
|
476
|
+
"oneapi:mock": "bigfish api generate mock",
|
|
477
|
+
"oneapi:service": "bigfish api generate service",
|
|
478
|
+
"prepare": "husky install",
|
|
479
|
+
"setup": "bigfish setup",
|
|
480
|
+
"test": "bigfish test"
|
|
481
|
+
},
|
|
482
|
+
"dependencies": {
|
|
483
|
+
"@alipay/bigfish": "^4.0.157",
|
|
484
|
+
"@alipay/tech-ui": "^3.2.2",
|
|
485
|
+
"@monaco-editor/react": "^4.4.6",
|
|
486
|
+
"antd": "conch-v5"
|
|
487
|
+
},
|
|
488
|
+
"devDependencies": {
|
|
489
|
+
"@ali/ci": "^4.43.0",
|
|
490
|
+
"cross-env": "^7.0.3",
|
|
491
|
+
"husky": "^8.0.1",
|
|
492
|
+
"lint-staged": "^13.0.3",
|
|
493
|
+
"prettier": "^2.7.1",
|
|
494
|
+
"typescript": "^4.1.2"
|
|
495
|
+
},
|
|
496
|
+
"engines": {
|
|
497
|
+
"install-node": "16"
|
|
498
|
+
},
|
|
499
|
+
"ci": {
|
|
500
|
+
"type": "aci",
|
|
501
|
+
"coverage": false
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
`,
|
|
505
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Injectable, Autowired } from '@opensumi/di';
|
|
3
|
+
import { CommandService, CommandRegistry, Command } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
import { AiGPTBackSerivcePath } from '../../common';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class AiSumiService {
|
|
9
|
+
@Autowired(AiGPTBackSerivcePath)
|
|
10
|
+
aiBackService: any;
|
|
11
|
+
|
|
12
|
+
@Autowired(CommandService)
|
|
13
|
+
protected readonly commandService: CommandService;
|
|
14
|
+
|
|
15
|
+
@Autowired(CommandRegistry)
|
|
16
|
+
protected readonly commandRegistryService: CommandRegistry;
|
|
17
|
+
|
|
18
|
+
private taskPrompt(command: string[]) {
|
|
19
|
+
return `
|
|
20
|
+
在我的系统中有一些 Command,通过这些命令可以实现一些功能。请通过分析我的问题,找到我想要实现的功能,匹配适合的 Command。
|
|
21
|
+
请参照下面的示例问答,按照示例回答的格式返回。如果找不到合适的命令,请返回未找到合适命令。
|
|
22
|
+
以下是系统内的全部 Command: ${command.join('、')}、workbench.action.openGlobalKeybindings、editor.action.setEncoding`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async message(input: string): Promise<Command | undefined> {
|
|
26
|
+
const commands = this.commandRegistryService.getCommands();
|
|
27
|
+
const commandIds = commands.filter((c) => !!c.label).map((c) => c.delegate || c.id);
|
|
28
|
+
const step = 50;
|
|
29
|
+
const partCommands = Array.from({ length: Math.round(commandIds.length / step) }, (_, index) => index).map((i) =>
|
|
30
|
+
commandIds.slice(i * step, (i + 1) * step),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const res = await Promise.all(partCommands.map((c) => this.requestCommand(c, input)));
|
|
34
|
+
const passibleCommands = res.filter((r) => !!r);
|
|
35
|
+
|
|
36
|
+
let finalCommand = passibleCommands[0];
|
|
37
|
+
|
|
38
|
+
if (passibleCommands.length > 1) {
|
|
39
|
+
finalCommand = await this.requestCommand(passibleCommands, input);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return commands.find((c) => c.id === finalCommand || c.delegate === finalCommand);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async requestCommand(commands: string[], question: string) {
|
|
46
|
+
const cotPrompt = `
|
|
47
|
+
${this.taskPrompt(commands)}
|
|
48
|
+
提问: 打开全局快捷键配置
|
|
49
|
+
回答: 通过分析需求「打开全局快捷键配置」, 可以获取到一些关键词: open、keybinding、global。通过这些关键词可以在 Command 的列表内匹配到相关的命令是: \`workbench.action.openGlobalKeybindings\`
|
|
50
|
+
提问: 增加字体大小
|
|
51
|
+
回答: 通过分析需求「增加字体大小」,可以获取到一些关键词:font、zoomIn、zoomOut。通过这些关键词,无法在 Command 列表中找到合适的命令。
|
|
52
|
+
提问: ${question}`;
|
|
53
|
+
|
|
54
|
+
const res = await this.aiBackService.aiAntGlm(cotPrompt);
|
|
55
|
+
const answerCommand = this.matchCommand(res.data);
|
|
56
|
+
return commands.find((c) => c === answerCommand) || '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private matchCommand(answer: string): string {
|
|
60
|
+
const commandReg = /`(?<command>\S+)`/;
|
|
61
|
+
const command = commandReg.exec(answer);
|
|
62
|
+
|
|
63
|
+
return command ? command.groups?.command || '' : '';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { URI, MaybePromise, Emitter, Event } from '@opensumi/ide-core-browser';
|
|
3
|
+
import { IEditorDocumentModelContentProvider } from '@opensumi/ide-editor/lib/browser/index';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class AiCodeDocumentProvider implements IEditorDocumentModelContentProvider {
|
|
7
|
+
private _onDidChangeContent = new Emitter<URI>();
|
|
8
|
+
|
|
9
|
+
onDidChangeContent: Event<URI> = this._onDidChangeContent.event;
|
|
10
|
+
|
|
11
|
+
provideEditorDocumentModelContent(uri: URI, encoding?: string): MaybePromise<string> {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
isReadonly(uri: URI): MaybePromise<boolean> {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
handlesScheme(scheme: string) {
|
|
20
|
+
return scheme === 'AI';
|
|
21
|
+
}
|
|
22
|
+
}
|