improved monaco suggestions meachnism and fixed documentation generation

pull/5100/head
Stéphane Tetsing 2 months ago
parent 3794139c61
commit 0e9aa7336d
  1. 3
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  2. 14
      apps/remix-ide/src/assets/list.json
  3. 1450
      apps/remixdesktop/package-lock.json
  4. 1166
      apps/remixdesktop/yarn.lock
  5. 1
      libs/remix-ai-core/src/inferencers/remote/remoteInference.ts
  6. 31
      libs/remix-ui/editor/src/lib/providers/completionTimer.ts
  7. 57
      libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
  8. 6
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  9. 3
      package.json
  10. 10139
      yarn.lock

@ -118,6 +118,7 @@ export class RemixAIPlugin extends ViewPlugin {
} }
if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result }) if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" }) // this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
return result
} }
async code_explaining(prompt: string): Promise<any> { async code_explaining(prompt: string): Promise<any> {
@ -137,6 +138,7 @@ export class RemixAIPlugin extends ViewPlugin {
} }
if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result }) if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" }) // this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
return result
} }
async error_explaining(prompt: string): Promise<any> { async error_explaining(prompt: string): Promise<any> {
@ -155,6 +157,7 @@ export class RemixAIPlugin extends ViewPlugin {
} }
if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result }) if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" }) // this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
return result
} }
async code_insertion(msg_pfx: string, msg_sfx: string): Promise<any> { async code_insertion(msg_pfx: string, msg_sfx: string): Promise<any> {

@ -1022,9 +1022,21 @@
"urls": [ "urls": [
"dweb:/ipfs/QmS5JdeXtYhGBvdgNTLWuBNHupyP623X4sf43fRbrgiTaA" "dweb:/ipfs/QmS5JdeXtYhGBvdgNTLWuBNHupyP623X4sf43fRbrgiTaA"
] ]
},
{
"path": "soljson-v0.8.27+commit.40a35a09.js",
"version": "0.8.27",
"build": "commit.40a35a09",
"longVersion": "0.8.27+commit.40a35a09",
"keccak256": "0x68c7a06651a847fc9a60886a6ba590a2b20d87f2d4f9570bf70fbb2b901e7713",
"sha256": "0xd91c08277f801321af4e80958015aea18b41c01d2c6a38310a23014485b0e51c",
"urls": [
"dweb:/ipfs/QmVTALD1WUQwRvEL19jgwrEFyBJMQmy9z32zvT6TAtYPY1"
]
} }
], ],
"releases": { "releases": {
"0.8.27": "soljson-v0.8.27+commit.40a35a09.js",
"0.8.26": "soljson-v0.8.26+commit.8a97fa7a.js", "0.8.26": "soljson-v0.8.26+commit.8a97fa7a.js",
"0.8.25": "soljson-v0.8.25+commit.b61c2a91.js", "0.8.25": "soljson-v0.8.25+commit.b61c2a91.js",
"0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js", "0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js",
@ -1119,5 +1131,5 @@
"0.4.0": "soljson-v0.4.0+commit.acd334c9.js", "0.4.0": "soljson-v0.4.0+commit.acd334c9.js",
"0.3.6": "soljson-v0.3.6+commit.3fc68da5.js" "0.3.6": "soljson-v0.3.6+commit.3fc68da5.js"
}, },
"latestRelease": "0.8.26" "latestRelease": "0.8.27"
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -23,7 +23,6 @@ export class RemoteInferencer implements ICompletions {
this.event.emit("onInference") this.event.emit("onInference")
const requesURL = rType === AIRequestType.COMPLETION ? this.completion_url : this.api_url const requesURL = rType === AIRequestType.COMPLETION ? this.completion_url : this.api_url
const userPrompt = data.data[0] const userPrompt = data.data[0]
console.log('userPrompt reuesting...')
try { try {
const result = await axios(requesURL, { const result = await axios(requesURL, {

@ -1,31 +0,0 @@
export class CompletionTimer {
private duration: number;
private timerId: NodeJS.Timeout | null = null;
private callback: () => void;
constructor(duration: number, callback: () => void) {
this.duration = duration;
this.callback = callback;
}
start() {
if (this.timerId) {
console.error("Timer is already running.");
return;
}
this.timerId = setTimeout(() => {
this.callback();
this.timerId = null;
}, this.duration);
}
stop() {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
} else {
console.error("Timer is not running.");
}
}
}

@ -1,10 +1,11 @@
/* eslint-disable no-control-regex */ /* eslint-disable no-control-regex */
import { EditorUIProps, monacoTypes } from '@remix-ui/editor'; import { EditorUIProps, monacoTypes } from '@remix-ui/editor';
import { CompletionTimer } from './completionTimer'; import { CompletionTimeout } from './completionTimer';
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import { slice } from 'lodash'; import { slice } from 'lodash';
import { activateService } from '@remixproject/plugin-utils'; import { activateService } from '@remixproject/plugin-utils';
import { any } from 'async';
const _paq = (window._paq = window._paq || []) const _paq = (window._paq = window._paq || [])
export class RemixInLineCompletionProvider implements monacoTypes.languages.InlineCompletionsProvider { export class RemixInLineCompletionProvider implements monacoTypes.languages.InlineCompletionsProvider {
@ -12,18 +13,36 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
monaco: any monaco: any
completionEnabled: boolean completionEnabled: boolean
task: string task: string
currentCompletion currentCompletion: any
private lastRequestTime: number = 0;
private readonly minRequestInterval: number = 200;
constructor(props: any, monaco: any) { constructor(props: any, monaco: any) {
this.props = props this.props = props
this.monaco = monaco this.monaco = monaco
this.completionEnabled = true this.completionEnabled = true
this.currentCompletion = {
text: '',
item: any,
task : this.task,
displayed: false,
accepted: false
}
} }
async provideInlineCompletions(model: monacoTypes.editor.ITextModel, position: monacoTypes.Position, context: monacoTypes.languages.InlineCompletionContext, token: monacoTypes.CancellationToken): Promise<monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>> { async provideInlineCompletions(model: monacoTypes.editor.ITextModel, position: monacoTypes.Position, context: monacoTypes.languages.InlineCompletionContext, token: monacoTypes.CancellationToken): Promise<monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>> {
if (context.selectedSuggestionInfo) { if (context.selectedSuggestionInfo) {
return; return { items: []};
}
const currentTime = Date.now();
const timeSinceLastRequest = currentTime - this.lastRequestTime;
if (timeSinceLastRequest < this.minRequestInterval) {
return { items: []}; // dismiss the request
} }
this.lastRequestTime = Date.now();
const getTextAtLine = (lineNumber) => { const getTextAtLine = (lineNumber) => {
const lineRange = model.getFullModelRange().setStartPosition(lineNumber, 1).setEndPosition(lineNumber + 1, 1); const lineRange = model.getFullModelRange().setStartPosition(lineNumber, 1).setEndPosition(lineNumber + 1, 1);
return model.getValueInRange(lineRange); return model.getValueInRange(lineRange);
@ -73,9 +92,11 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
insertText: parsedData insertText: parsedData
}; };
this.currentCompletion.text = parsedData
this.currentCompletion.item = item
return { return {
items: [item], items: [item],
enableForwardStability: true enableForwardStability: false
} }
} }
} catch (e) { } catch (e) {
@ -89,7 +110,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
word.split('\n').at(-1).trimStart().startsWith('*/') || word.split('\n').at(-1).trimStart().startsWith('*/') ||
word.split('\n').at(-1).endsWith(';') word.split('\n').at(-1).endsWith(';')
){ ){
return; // do not do completion on single and multiline comment return { items: []}; // do not do completion on single and multiline comment
} }
// abort if there is a signal // abort if there is a signal
@ -97,11 +118,6 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
return return
} }
// abort if the completion is not enabled
if (!this.completionEnabled) {
return
}
if (word.replace(/ +$/, '').endsWith('\n')){ if (word.replace(/ +$/, '').endsWith('\n')){
// Code insertion // Code insertion
try { try {
@ -112,14 +128,12 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
insertText: generatedText insertText: generatedText
}; };
this.currentCompletion.text = generatedText
this.completionEnabled = false this.currentCompletion.item = item
const handleCompletionTimer = new CompletionTimer(100, () => { this.completionEnabled = true });
handleCompletionTimer.start()
return { return {
items: [item], items: [item],
enableForwardStability: true enableForwardStability: false,
} }
} }
catch (err){ catch (err){
@ -131,6 +145,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
// Code completion // Code completion
this.task = 'code_completion' this.task = 'code_completion'
const output = await this.props.plugin.call('remixAI', 'code_completion', word) const output = await this.props.plugin.call('remixAI', 'code_completion', word)
console.log('output', output)
const generatedText = output const generatedText = output
let clean = generatedText let clean = generatedText
@ -141,13 +156,10 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
clean = this.process_completion(clean) clean = this.process_completion(clean)
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
insertText: clean insertText: clean,
}; };
this.currentCompletion.text = clean
// handle the completion timer by locking suggestions request for 2 seconds this.currentCompletion.item = item
this.completionEnabled = false
const handleCompletionTimer = new CompletionTimer(100, () => { this.completionEnabled = true });
handleCompletionTimer.start()
return { return {
items: [item], items: [item],
@ -171,10 +183,11 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
} }
handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void { handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void {
this.currentCompletion = { 'item':item, 'task':this.task } this.currentCompletion.displayed = true
_paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_did_show']) _paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_did_show'])
} }
handlePartialAccept?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, acceptedCharacters: number): void { handlePartialAccept?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, acceptedCharacters: number): void {
this.currentCompletion.accepted = true
_paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_partial_accept']) _paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_partial_accept'])
} }
freeInlineCompletions(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>): void { freeInlineCompletions(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>): void {

@ -709,7 +709,7 @@ export const EditorUI = (props: EditorUIProps) => {
// Check if the change matches the current completion // Check if the change matches the current completion
if (changes.some(change => change.text === inlineCompletionProvider.currentCompletion.item.insertText)) { if (changes.some(change => change.text === inlineCompletionProvider.currentCompletion.item.insertText)) {
_paq.push(['trackEvent', 'ai', 'solcoder', inlineCompletionProvider.currentCompletion.task + '_accepted']) _paq.push(['trackEvent', 'ai', 'solcoder', inlineCompletionProvider.currentCompletion.task + '_accepted'])
inlineCompletionProvider.currentCompletion = null; console.log('Accepted completion', inlineCompletionProvider.currentCompletion)
} }
} }
}); });
@ -777,11 +777,9 @@ export const EditorUI = (props: EditorUIProps) => {
const file = await props.plugin.call('fileManager', 'getCurrentFile') const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file) const content = await props.plugin.call('fileManager', 'readFile', file)
const message = intl.formatMessage({ id: 'editor.generateDocumentationByAI' }, { content, currentFunction: currentFunction.current }) const message = intl.formatMessage({ id: 'editor.generateDocumentationByAI' }, { content, currentFunction: currentFunction.current })
const cm = await props.plugin.call('remixAI', 'code_explaining', message) const cm = await await props.plugin.call('remixAI', 'code_explaining', message)
console.log(cm)
const natSpecCom = "\n" + extractNatspecComments(cm) const natSpecCom = "\n" + extractNatspecComments(cm)
console.log(natSpecCom)
const cln = await props.plugin.call('codeParser', "getLineColumnOfNode", currenFunctionNode) const cln = await props.plugin.call('codeParser', "getLineColumnOfNode", currenFunctionNode)
const range = new monacoRef.current.Range(cln.start.line, cln.start.column, cln.start.line, cln.start.column) const range = new monacoRef.current.Range(cln.start.line, cln.start.column, cln.start.line, cln.start.column)
const lines = natSpecCom.split('\n') const lines = natSpecCom.split('\n')

@ -166,12 +166,9 @@
"jszip": "^3.6.0", "jszip": "^3.6.0",
"just-once": "^2.2.0", "just-once": "^2.2.0",
"latest-version": "^5.1.0", "latest-version": "^5.1.0",
"llama-node": "^0.1.6",
"merge": "^2.1.1", "merge": "^2.1.1",
"node-llama-cpp": "^2.8.11",
"npm-install-version": "^6.0.2", "npm-install-version": "^6.0.2",
"octokit": "^3.1.2", "octokit": "^3.1.2",
"openai": "^3.3.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"prettier-plugin-solidity": "^1.0.0-beta.24", "prettier-plugin-solidity": "^1.0.0-beta.24",

10139
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save