diff --git a/apps/remix-ide/src/app/plugins/solcoderAI.tsx b/apps/remix-ide/src/app/plugins/solcoderAI.tsx index 94687d3440e..19e618d0705 100644 --- a/apps/remix-ide/src/app/plugins/solcoderAI.tsx +++ b/apps/remix-ide/src/app/plugins/solcoderAI.tsx @@ -15,7 +15,7 @@ const profile = { name: 'solcoder', displayName: 'solcoder', description: 'solcoder', - methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion"], + methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "contract_generation"], events: [], maintainedBy: 'Remix', } @@ -218,6 +218,42 @@ export class SolCoder extends Plugin { } } + async contract_generation(prompt): Promise { + this.emit("aiInfering") + let result + try { + result = await( + await fetch(this.api_url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ "data":[ + prompt, // string in 'context_code' Textbox component + "contract_generation", + false, // boolean in 'stream_result' Checkbox component + 2000, // number (numeric value between 0 and 2000) in 'max_new_tokens' Slider component + 0.9, // number (numeric value between 0.01 and 1) in 'temperature' Slider component + 0.90, // number (numeric value between 0 and 1) in 'top_p' Slider component + 50, // number (numeric value between 1 and 200) in 'top_k' Slider component + ]}), + }) + ).json() + + if ("error" in result){ + return result + } + return result.data + + } catch (e) { + this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `Unable to get a response ${e.message}` }) + return + } finally { + this.emit("aiInferingDone") + } + } + _build_solgpt_promt(user_promt:string){ if (this.solgpt_chat_history.length === 0){ return user_promt diff --git a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts index 92c79914b53..4ce3dd83cca 100644 --- a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts +++ b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts @@ -14,10 +14,12 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli props: EditorUIProps monaco: any completionEnabled: boolean + isGeneratingContract: boolean constructor(props: any, monaco: any) { this.props = props this.monaco = monaco this.completionEnabled = true + this.isGeneratingContract = false } async provideInlineCompletions(model: monacoTypes.editor.ITextModel, position: monacoTypes.Position, context: monacoTypes.languages.InlineCompletionContext, token: monacoTypes.CancellationToken): Promise> { @@ -44,6 +46,28 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli endColumn: getTextAtLine(model.getLineCount()).length + 1, }); + if (this.isSolidityComment(word) && + word.includes("sol-gen") && + this.isGeneratingContract===false && + word.split('\n')[word.split('\n').length-1].trim()===""){ + + this.isGeneratingContract = true + console.log("new contract generation") + const output = await this.props.plugin.call('solcoder', 'contract_generation', word) + _paq.push(['trackEvent', 'ai', 'solcoder', 'contract_generation']) + const handleCompletionTimer = new CompletionTimer(5000, () => { this.isGeneratingContract = false }); + handleCompletionTimer.start() + + const item: monacoTypes.languages.InlineCompletion = { + insertText: output[0] + }; + + return { + items: [item], + enableForwardStability: true + } + } + if (!word.endsWith(' ') && !word.endsWith('.') && !word.endsWith('(')) { @@ -60,6 +84,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli try { const split = word.split('\n') if (split.length < 2) return + const ask = split[split.length - 2].trimStart() if (split[split.length - 1].trim() === '' && ask.startsWith('///')) { // use the code generation model, only take max 1000 word as context @@ -158,6 +183,20 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli } } + isSolidityComment(text: string): boolean { + const joinedText = text.trim().replace(/\n\s*/g, ' '); + + const singleLineComment = /^\/\/.*$/; + const multiLineComment = /^\/\*[\s\S]*\*\/$/; + const singleLineNatSpec = /^\/\/\/.*$/; + const multiLineNatSpec = /^\/\*\*[\s\S]*\*\/$/; + + return singleLineComment.test(joinedText) || + multiLineComment.test(joinedText) || + singleLineNatSpec.test(joinedText) || + multiLineNatSpec.test(joinedText); + } + process_completion(data: any) { let clean = data.split('\n')[0].startsWith('\n') ? [data.split('\n')[0], data.split('\n')[1]].join('\n'): data.split('\n')[0]