|
10 | 10 | * |
11 | 11 | */ |
12 | 12 | 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' |
14 | 15 |
|
15 | 16 | const keyWords = [ |
16 | 17 | 'state', |
@@ -176,78 +177,43 @@ const generateBaseReference = () => { |
176 | 177 | const { dataSource = [], utils = [], globalState = [] } = useResource().appSchemaState |
177 | 178 | const { state, methods } = useCanvas().getPageSchema() |
178 | 179 | 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)) |
222 | 187 | return referenceContext |
223 | 188 | } |
224 | 189 |
|
225 | 190 | const fetchAiInlineCompletion = (codeBeforeCursor, codeAfterCursor) => { |
226 | | - const referenceContext = generateBaseReference() |
227 | 191 | 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, |
236 | 200 | messages: [ |
237 | 201 | { |
238 | 202 | 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) |
246 | 206 | } |
247 | 207 | ], |
248 | 208 | stream: false |
249 | | - }) |
250 | | - }) |
| 209 | + }, |
| 210 | + { |
| 211 | + headers: { |
| 212 | + 'Content-Type': 'application/json', |
| 213 | + Authorization: `Bearer ${apiKey}` |
| 214 | + } |
| 215 | + } |
| 216 | + ) |
251 | 217 | } |
252 | 218 |
|
253 | 219 | const initInlineCompletion = (monacoInstance, editorModel) => { |
@@ -303,14 +269,8 @@ const initInlineCompletion = (monacoInstance, editorModel) => { |
303 | 269 | // 节流操作,防止接口一直被请求 |
304 | 270 | requestAllowed.value = false |
305 | 271 | fetchAiInlineCompletion(codeBeforeCursor, codeAfterCursor) |
306 | | - .then((response) => response.json()) |
307 | 272 | .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() |
314 | 274 | const wordContentIndex = insertText.indexOf(wordContent) |
315 | 275 | if (wordContentIndex === -1) { |
316 | 276 | insertText = `${wordContent}${insertText}\n` |
|
0 commit comments