Skip to content

Commit 3c39e54

Browse files
committed
feat(ai-completions): fix review bugs
1 parent e4cb817 commit 3c39e54

3 files changed

Lines changed: 83 additions & 72 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
你是一个JavaScript代码补全器,可以使用JS和ES的语法
2+
3+
以下是一些通用的协议:
4+
常规属性如:{ width: '300px' }
5+
一. 变量引用
6+
{ width: { type: 'JSExpression', value: 'this.state.xxx' }
7+
即当type为JSExpression,取其value并将value的值当做变量调用
8+
二. 方法引用
9+
{ onClickNew: { type: 'JSFunction', value: 'function onClickNew() {}' }
10+
即当type为JSFunction,取其value并将value的值函数调用
11+
以下是一些依赖,调用均以this.开头:
12+
1. 数据源
13+
数据源是定义的数据模型
14+
const dataSource=$dataSource$
15+
调用方式为: this.dataSource.xxx
16+
2. 工具类
17+
工具类是通用的调用方法或npm依赖
18+
const utils=$utils$
19+
调用方式为: this.utils.xxx
20+
utils有两种类型
21+
type为npm时,读取content内容,可构造如下引用,例如content中package(依赖包名)为@opentiny/vue,destructuring(解构)为true,exportName(导出组件名称)为Notify,实际引用方式是import { Notify } from '@opentiny/vue';
22+
type为function时,读取content内容,当content.type为JSFunction则将value视为JS方法并调用,其他可参考通用的协议
23+
3. 全局变量
24+
全局变量是使用pinia创建的变量
25+
const stores=$globalState$
26+
调用方式为: this.stores.xxx
27+
4. JS变量
28+
js变量
29+
const state=$state$
30+
调用方式为: this.state.xxx
31+
5. JS方法
32+
js方法
33+
const methods=$methods$
34+
调用方式为: this.xxx
35+
36+
以上依赖中没有的,则不能调用,如utils中没有axios,则axios不能使用
37+
38+
以下是当前选中的组件
39+
$currentSchema$
40+
请理解当前组件,componentName为组件名称,组件包括tinyVue组件、ElementPlus组件,和基本html元素
41+
对象中的ref属性即vue组件的ref属性,如ref值为testForm,使用方式为this.$('testForm')
42+
props表示组件的属性,是一个对象,对应vue组件的defineProps和defineEmits中的内容
43+
props中以on开头的表示其传递的是方法,如onClick,其值可以参考通用协议
44+
props中没有以on开头的则是普通属性,如tinyInput组件中的placeholder
45+
props的属性中值为对象,且包含type和value属性,type为JSExpression和JSFunction时,value的值则参考通用协议取用
46+
47+
直接上下文如下:
48+
$codeBeforeCursor$<cursor>$codeAfterCursor$
49+
请从<cursor>(光标位置)处进行补全
50+
注意如果是函数时,须以function关键字开头,不使用箭头函数
51+
请只返回代码,且只返回一个示例,不需要思考过程和解释

packages/common/js/completion.js

Lines changed: 29 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
*
1111
*/
1212
import { ref } from 'vue'
13-
import { useCanvas, useResource, getMergeMeta } from '@opentiny/tiny-engine-meta-register'
13+
import { useCanvas, useResource, getMergeMeta, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
14+
import completion from './completion-files/context.md?raw'
1415

1516
const keyWords = [
1617
'state',
@@ -176,78 +177,43 @@ const generateBaseReference = () => {
176177
const { dataSource = [], utils = [], globalState = [] } = useResource().appSchemaState
177178
const { state, methods } = useCanvas().getPageSchema()
178179
const currentSchema = useCanvas().getCurrentSchema()
179-
let referenceContext = `以下是一些通用的协议:
180-
\n常规属性如:{ width: '300px' }
181-
\n1.变量引用
182-
\n{ width: { type: 'JSExpression', value: 'this.state.xxx' }}
183-
\n即当type为JSExpression,取其value并将value的值当做变量调用
184-
\n2.方法引用
185-
\n{ onClickNew: { type: 'JSFunction', value: 'function onClickNew() {}' }}
186-
\n即当type为JSFunction,取其value并将value的值函数调用
187-
\n以下是一些依赖,调用均以this.开头:\n`
188-
if (dataSource.length) {
189-
referenceContext += `数据源是定义的数据模型\nconst dataSource=${JSON.stringify(
190-
dataSource
191-
)}\n调用方式为: this.dataSource.xxx\n`
192-
}
193-
if (utils.length) {
194-
referenceContext += `工具类是通用的调用方法或npm依赖
195-
\nconst utils=${JSON.stringify(utils)}
196-
\n调用方式为: this.utils.xxx
197-
\nutils有两种类型
198-
\ntype为npm时,读取content内容,可构造如下引用,例如content中package(依赖包名)为@opentiny/vue,destructuring(解构)为true,exportName(导出组件名称)为Notify,实际引用方式是import { Notify } from '@opentiny/vue';
199-
\ntype为function时,读取content内容,当content.type为JSFunction则将value视为JS方法并调用,其他可参考通用的协议\n`
200-
}
201-
if (globalState.length) {
202-
referenceContext += `全局变量是使用pinia创建的变量\nconst stores=${JSON.stringify(
203-
globalState
204-
)}\n调用方式为: this.stores.xxx\n`
205-
}
206-
if (Object.keys(state).length) {
207-
referenceContext += `js变量\nconst state=${JSON.stringify(state)}\n调用方式为: this.state.xxx\n`
208-
}
209-
if (Object.keys(methods).length) {
210-
referenceContext += `js方法\nconst methods=${JSON.stringify(methods)}\n调用方式为: this.xxx\n`
211-
}
212-
referenceContext += `以上依赖中没有的,则不能调用,如utils中没有axios,则axios不能使用\n`
213-
if (currentSchema) {
214-
referenceContext += `以下是当前选中的组件
215-
\n${JSON.stringify(currentSchema)}
216-
\n请理解当前组件,componentName为组件名称,组件均为tinyVue组件,和基本html元素
217-
\n该对象中的ref属性为vue组件的ref属性,如ref值为testForm,使用方式为this.$('testForm')
218-
\nprops表示组件的属性,是一个对象,对应vue组件的defineProps和defineEmits中的内容
219-
\nprops中以on开头的表示其传递的是方法,如onClick,其值可以参考通用协议
220-
\nprops中没有以on开头的则是普通属性,如onClick,其值中满足type为JSExpression和JSFunction的可以参考通用协议\n`
221-
}
180+
let referenceContext = completion
181+
referenceContext = referenceContext.replace('$dataSource$', JSON.stringify(dataSource))
182+
referenceContext = referenceContext.replace('$utils$', JSON.stringify(utils))
183+
referenceContext = referenceContext.replace('$globalState$', JSON.stringify(globalState))
184+
referenceContext = referenceContext.replace('$state$', JSON.stringify(state))
185+
referenceContext = referenceContext.replace('$methods$', JSON.stringify(methods))
186+
referenceContext = referenceContext.replace('$currentSchema$', JSON.stringify(currentSchema))
222187
return referenceContext
223188
}
224189

225190
const fetchAiInlineCompletion = (codeBeforeCursor, codeAfterCursor) => {
226-
const referenceContext = generateBaseReference()
227191
const { modelName, apiKey, url } = getMergeMeta('engine.plugins.pagecontroller')?.options?.AIModel || {}
228-
return fetch(`${url ?? 'https://agent.opentiny.design/api/v1/ai/chat/completions'}`, {
229-
method: 'POST',
230-
headers: {
231-
'Content-Type': 'application/json',
232-
Authorization: `Bearer ${apiKey ?? 'sk-1234'}`
233-
},
234-
body: JSON.stringify({
235-
model: modelName ?? 'internvl3-14b',
192+
if (!modelName || !apiKey || !url) {
193+
throw new Error(`"modelName","apiKey","url" cannot be empty`)
194+
}
195+
const referenceContext = generateBaseReference()
196+
return getMetaApi(META_SERVICE.Http).post(
197+
url,
198+
{
199+
model: modelName,
236200
messages: [
237201
{
238202
role: 'user',
239-
content: `你是一个JavaScript代码补全器,可以使用JS和ES的语法
240-
\n${referenceContext}
241-
\n直接上下文如下:
242-
\n${codeBeforeCursor}<cursor>${codeAfterCursor}
243-
\n请从<cursor>(光标位置)处进行补全
244-
\n返回代码不要包含上下文代码,不需要多余代码,注意如果是函数时,须以这种格式:function xxx() {}
245-
\n如果有多个示例,只选择其中一个,不需要返回思考过程和解释`
203+
content: referenceContext
204+
.replace('$codeBeforeCursor$', codeBeforeCursor)
205+
.replace('$codeAfterCursor$', codeAfterCursor)
246206
}
247207
],
248208
stream: false
249-
})
250-
})
209+
},
210+
{
211+
headers: {
212+
'Content-Type': 'application/json',
213+
Authorization: `Bearer ${apiKey}`
214+
}
215+
}
216+
)
251217
}
252218

253219
const initInlineCompletion = (monacoInstance, editorModel) => {
@@ -303,14 +269,8 @@ const initInlineCompletion = (monacoInstance, editorModel) => {
303269
// 节流操作,防止接口一直被请求
304270
requestAllowed.value = false
305271
fetchAiInlineCompletion(codeBeforeCursor, codeAfterCursor)
306-
.then((response) => response.json())
307272
.then((res) => {
308-
let insertText = res.choices[0].message.content
309-
.replace(/.*\n/, '')
310-
.replaceAll('```', '')
311-
.replace('javascript', '')
312-
.replace('typescript', '')
313-
.trim()
273+
let insertText = res.choices[0].message.content.trim()
314274
const wordContentIndex = insertText.indexOf(wordContent)
315275
if (wordContentIndex === -1) {
316276
insertText = `${wordContent}${insertText}\n`

packages/plugins/script/meta.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export default {
88
options: {
99
enableAICompletion: true,
1010
AIModel: {
11-
modelName: '',
12-
apiKey: '',
13-
url: ''
11+
modelName: 'internvl3-14b',
12+
apiKey: 'sk-1234',
13+
url: 'https://agent.opentiny.design/api/v1/ai/chat/completions'
1414
}
1515
},
1616
confirm: 'close' // 当点击插件栏切换或关闭前是否需要确认, 会调用插件中confirm值指定的方法,e.g. 此处指向 close方法,会调用插件的close方法执行确认逻辑

0 commit comments

Comments
 (0)