Merge pull request #4809 from ethereum/ask_sol_gpt

switched open gpt to solcoder for error explaining
pull/4865/head
Aniket 5 months ago committed by GitHub
commit 2a4235b78a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      apps/circuit-compiler/src/app/components/container.tsx
  2. 2
      apps/circuit-compiler/src/app/components/feedbackAlert.tsx
  3. 6
      apps/remix-ide/src/app.js
  4. 49
      apps/remix-ide/src/app/plugins/openaigpt.tsx
  5. 44
      apps/remix-ide/src/app/plugins/solcoderAI.tsx
  6. 1
      apps/remix-ide/src/remixAppManager.js
  7. 1
      apps/remix-ide/src/remixEngine.js
  8. 2
      apps/vyper/src/app/components/CompileErrorCard.tsx
  9. 4
      apps/vyper/src/app/utils/remix-client.tsx
  10. 3
      libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
  11. 8
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  12. 6
      libs/remix-ui/renderer/src/lib/renderer.tsx
  13. 5
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  14. 3
      libs/remix-ui/terminal/src/lib/terminalWelcome.tsx

@ -73,7 +73,7 @@ export function Container () {
explain why the error occurred and how to fix it. explain why the error occurred and how to fix it.
` `
// @ts-ignore // @ts-ignore
await circuitApp.plugin.call('openaigpt', 'message', message) await circuitApp.plugin.call('solcoder', 'error_explaining', message)
} else { } else {
const message = ` const message = `
error message: ${error} error message: ${error}
@ -81,7 +81,7 @@ export function Container () {
explain why the error occurred and how to fix it. explain why the error occurred and how to fix it.
` `
// @ts-ignore // @ts-ignore
await circuitApp.plugin.call('openaigpt', 'message', message) await circuitApp.plugin.call('solcoder', 'error_explaining', message)
} }
} else { } else {
const error = report.message const error = report.message
@ -91,7 +91,7 @@ export function Container () {
explain why the error occurred and how to fix it. explain why the error occurred and how to fix it.
` `
// @ts-ignore // @ts-ignore
await circuitApp.plugin.call('openaigpt', 'message', message) await circuitApp.plugin.call('solcoder', 'error_explaining', message)
} }
} }

@ -24,7 +24,7 @@ export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) {
<span className="border border-success text-success btn-sm" onClick={(e) => { <span className="border border-success text-success btn-sm" onClick={(e) => {
e.stopPropagation() e.stopPropagation()
askGPT() askGPT()
}}>ASK GPT</span> }}>Ask RemixAI</span>
</div> </div>
</> </>
</RenderIf> </RenderIf>

@ -54,8 +54,6 @@ import { electronTemplates } from './app/plugins/electron/templatesPlugin'
import { xtermPlugin } from './app/plugins/electron/xtermPlugin' import { xtermPlugin } from './app/plugins/electron/xtermPlugin'
import { ripgrepPlugin } from './app/plugins/electron/ripgrepPlugin' import { ripgrepPlugin } from './app/plugins/electron/ripgrepPlugin'
import { compilerLoaderPlugin, compilerLoaderPluginDesktop } from './app/plugins/electron/compilerLoaderPlugin' import { compilerLoaderPlugin, compilerLoaderPluginDesktop } from './app/plugins/electron/compilerLoaderPlugin'
import {OpenAIGpt} from './app/plugins/openaigpt'
import {SolCoder} from './app/plugins/solcoderAI' import {SolCoder} from './app/plugins/solcoderAI'
const isElectron = require('is-electron') const isElectron = require('is-electron')
@ -233,7 +231,6 @@ class AppComponent {
const contractFlattener = new ContractFlattener() const contractFlattener = new ContractFlattener()
// ----------------- AI -------------------------------------- // ----------------- AI --------------------------------------
const openaigpt = new OpenAIGpt()
const solcoder = new SolCoder() const solcoder = new SolCoder()
// ----------------- import content service ------------------------ // ----------------- import content service ------------------------
@ -352,7 +349,6 @@ class AppComponent {
contractFlattener, contractFlattener,
solidityScript, solidityScript,
templates, templates,
openaigpt,
solcoder, solcoder,
pluginStateLogger pluginStateLogger
]) ])
@ -512,7 +508,7 @@ class AppComponent {
await this.appManager.registerContextMenuItems() await this.appManager.registerContextMenuItems()
} }
) )
await this.appManager.activatePlugin(['solidity-script', 'openaigpt']) await this.appManager.activatePlugin(['solidity-script'])
await this.appManager.activatePlugin(['solcoder']) await this.appManager.activatePlugin(['solcoder'])

@ -1,49 +0,0 @@
import { Plugin } from '@remixproject/engine'
import { CreateChatCompletionResponse } from 'openai'
const _paq = (window._paq = window._paq || [])
const profile = {
name: 'openaigpt',
displayName: 'openaigpt',
description: 'openaigpt',
methods: ['message'],
events: [],
maintainedBy: 'Remix',
}
export class OpenAIGpt extends Plugin {
constructor() {
super(profile)
}
async message(prompt): Promise<CreateChatCompletionResponse> {
this.call('layout', 'maximizeTerminal')
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Waiting for GPT answer...' })
let result
try {
result = await (
await fetch('https://openai-gpt.remixproject.org', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt }),
})
).json()
} catch (e) {
this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` })
return
}
if (result && result.choices && result.choices.length) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result.choices[0].message.content })
} else if (result.error) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result.error })
} else {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'No response...' })
}
return result.data
}
}

@ -15,7 +15,7 @@ const profile = {
name: 'solcoder', name: 'solcoder',
displayName: 'solcoder', displayName: 'solcoder',
description: '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", "error_explaining"],
events: [], events: [],
maintainedBy: 'Remix', maintainedBy: 'Remix',
} }
@ -50,6 +50,8 @@ export class SolCoder extends Plugin {
async code_generation(prompt): Promise<any> { async code_generation(prompt): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
this.call('layout', 'maximizeTerminal') this.call('layout', 'maximizeTerminal')
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_generation'])
let result let result
try { try {
result = await( result = await(
@ -78,6 +80,9 @@ export class SolCoder extends Plugin {
async solidity_answer(prompt): Promise<any> { async solidity_answer(prompt): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
this.call('layout', 'maximizeTerminal') this.call('layout', 'maximizeTerminal')
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
_paq.push(['trackEvent', 'ai', 'solcoder', 'answering'])
let result let result
try { try {
const main_prompt = this._build_solgpt_promt(prompt) const main_prompt = this._build_solgpt_promt(prompt)
@ -112,6 +117,9 @@ export class SolCoder extends Plugin {
async code_explaining(prompt, context:string=""): Promise<any> { async code_explaining(prompt, context:string=""): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
this.call('layout', 'maximizeTerminal') this.call('layout', 'maximizeTerminal')
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
_paq.push(['trackEvent', 'ai', 'solcoder', 'explaining'])
let result let result
try { try {
result = await( result = await(
@ -138,6 +146,8 @@ export class SolCoder extends Plugin {
async code_completion(prompt, options:SuggestOptions=null): Promise<any> { async code_completion(prompt, options:SuggestOptions=null): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_completion'])
let result let result
try { try {
result = await( result = await(
@ -184,6 +194,8 @@ export class SolCoder extends Plugin {
async code_insertion(msg_pfx, msg_sfx): Promise<any> { async code_insertion(msg_pfx, msg_sfx): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_insertion'])
let result let result
try { try {
result = await( result = await(
@ -218,6 +230,36 @@ export class SolCoder extends Plugin {
} }
} }
async error_explaining(prompt): Promise<any> {
this.emit("aiInfering")
this.call('layout', 'maximizeTerminal')
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
_paq.push(['trackEvent', 'ai', 'solcoder', 'explaining'])
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, "error_explaining", false,2000,0.9,0.8,50]}),
})
).json()
if (result) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result.data[0] })
}
return result.data[0]
} catch (e) {
this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` })
return
} finally {
this.emit("aiInferingDone")
}
}
_build_solgpt_promt(user_promt:string){ _build_solgpt_promt(user_promt:string){
if (this.solgpt_chat_history.length === 0){ if (this.solgpt_chat_history.length === 0){
return user_promt return user_promt

@ -71,7 +71,6 @@ let requiredModules = [ // services + layout views + system views
'vyperCompilationDetails', 'vyperCompilationDetails',
'contractflattener', 'contractflattener',
'solidity-script', 'solidity-script',
'openaigpt',
'solcoder', 'solcoder',
'home', 'home',
'doc-viewer', 'doc-viewer',

@ -26,7 +26,6 @@ export class RemixEngine extends Engine {
if (name === 'compilerloader') return { queueTimeout: 60000 * 4 } if (name === 'compilerloader') return { queueTimeout: 60000 * 4 }
if (name === 'filePanel') return { queueTimeout: 60000 * 20 } if (name === 'filePanel') return { queueTimeout: 60000 * 20 }
if (name === 'fileManager') return { queueTimeout: 60000 * 20 } if (name === 'fileManager') return { queueTimeout: 60000 * 20 }
if (name === 'openaigpt') return { queueTimeout: 60000 * 2 }
if (name === 'solcoder') return { queueTimeout: 60000 * 2 } if (name === 'solcoder') return { queueTimeout: 60000 * 2 }
if (name === 'cookbookdev') return { queueTimeout: 60000 * 3 } if (name === 'cookbookdev') return { queueTimeout: 60000 * 3 }
return { queueTimeout: 10000 } return { queueTimeout: 10000 }

@ -21,7 +21,7 @@ export function CompileErrorCard(props: { output: any, plugin: RemixClient }) {
<div className="d-flex flex-column pt-3 align-items-end mb-2"> <div className="d-flex flex-column pt-3 align-items-end mb-2">
<div> <div>
<span className="border border-ai text-ai btn-sm" onClick={async () => await props.plugin.askGpt(props.output.message)}> <span className="border border-ai text-ai btn-sm" onClick={async () => await props.plugin.askGpt(props.output.message)}>
Ask GPT Ask RemixAI
</span> </span>
<span className="ml-3 pt-1 py-1"> <span className="ml-3 pt-1 py-1">
<CopyToClipboard content={props.output.message} className={`p-0 m-0 far fa-copy alert alert-danger`} direction={'top'} /> <CopyToClipboard content={props.output.message} className={`p-0 m-0 far fa-copy alert alert-danger`} direction={'top'} />

@ -6,7 +6,6 @@ import {Contract, compileContract} from './compiler'
import {ExampleContract} from '../components/VyperResult' import {ExampleContract} from '../components/VyperResult'
import EventEmitter from 'events' import EventEmitter from 'events'
export type VyperComplierAddress = 'https://vyper2.remixproject.org/' | 'http://localhost:8000/' export type VyperComplierAddress = 'https://vyper2.remixproject.org/' | 'http://localhost:8000/'
export class RemixClient extends PluginClient { export class RemixClient extends PluginClient {
private client = createClient<Api, Readonly<RemixApi>>(this) private client = createClient<Api, Readonly<RemixApi>>(this)
@ -66,11 +65,12 @@ export class RemixClient extends PluginClient {
return return
} }
try { try {
// TODO: remove! no formatting required since already handled on server
const formattedMessage = ` const formattedMessage = `
${message} ${message}
can you explain why this error occurred and how to fix it? can you explain why this error occurred and how to fix it?
` `
await this.client.call('openaigpt' as any, 'message', formattedMessage) await this.client.call('solcoder' as any, 'error_explaining', message)
} catch (err) { } catch (err) {
console.error('unable to askGpt') console.error('unable to askGpt')
console.error(err) console.error(err)

@ -66,7 +66,6 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
this.props.plugin.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '') }) this.props.plugin.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '') })
const data = await this.props.plugin.call('solcoder', 'code_generation', word) const data = await this.props.plugin.call('solcoder', 'code_generation', word)
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_generation'])
const parsedData = data[0].trimStart() //JSON.parse(data).trimStart() const parsedData = data[0].trimStart() //JSON.parse(data).trimStart()
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
@ -105,7 +104,6 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
// Code insertion // Code insertion
try { try {
const output = await this.props.plugin.call('solcoder', 'code_insertion', word, word_after) const output = await this.props.plugin.call('solcoder', 'code_insertion', word, word_after)
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_insertion'])
const generatedText = output[0] // no need to clean it. should already be const generatedText = output[0] // no need to clean it. should already be
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
@ -130,7 +128,6 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
try { try {
// Code completion // Code completion
const output = await this.props.plugin.call('solcoder', 'code_completion', word) const output = await this.props.plugin.call('solcoder', 'code_completion', word)
_paq.push(['trackEvent', 'ai', 'solcoder', 'code_completion'])
const generatedText = output[0] const generatedText = output[0]
let clean = generatedText let clean = generatedText

@ -723,8 +723,8 @@ 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 })
await props.plugin.call('openaigpt', 'message', message) await props.plugin.call('solcoder', 'code_explaining', message)
_paq.push(['trackEvent', 'ai', 'openai', 'generateDocumentation']) _paq.push(['trackEvent', 'ai', 'solcoder', 'generateDocumentation'])
}, },
} }
@ -739,8 +739,8 @@ 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.explainFunctionByAI' }, { content, currentFunction: currentFunction.current }) const message = intl.formatMessage({ id: 'editor.explainFunctionByAI' }, { content, currentFunction: currentFunction.current })
await props.plugin.call('openaigpt', 'message', message) await props.plugin.call('solcoder', 'code_explaining', message, content)
_paq.push(['trackEvent', 'ai', 'openai', 'explainFunction']) _paq.push(['trackEvent', 'ai', 'solcoder', 'explainFunction'])
}, },
} }

@ -75,8 +75,8 @@ export const Renderer = ({ message, opt = {}, plugin }: RendererProps) => {
try { try {
const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile) const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile)
const message = intl.formatMessage({ id: 'solidity.openaigptMessage' }, { content, messageText }) const message = intl.formatMessage({ id: 'solidity.openaigptMessage' }, { content, messageText })
await plugin.call('openaigpt', 'message', message) await plugin.call('solcoder', 'error_explaining', message)
_paq.push(['trackEvent', 'ai', 'openai', 'explainSolidityError']) _paq.push(['trackEvent', 'ai', 'solcoder', 'error_explaining_SolidityError'])
} catch (err) { } catch (err) {
console.error('unable to askGtp') console.error('unable to askGtp')
console.error(err) console.error(err)
@ -111,7 +111,7 @@ export const Renderer = ({ message, opt = {}, plugin }: RendererProps) => {
onClick={() => { askGtp() }} onClick={() => { askGtp() }}
style={{ borderColor: "var(--ai)" }} style={{ borderColor: "var(--ai)" }}
> >
ASK GPT Ask RemixAI
</span> </span>
</div> </div>

@ -235,10 +235,11 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
try { try {
if (script.trim().startsWith('git')) { if (script.trim().startsWith('git')) {
// await this.call('git', 'execute', script) code might be used in the future // await this.call('git', 'execute', script) code might be used in the future
// TODO: rm gpt or redirect gpt to sol-pgt
} else if (script.trim().startsWith('gpt')) { } else if (script.trim().startsWith('gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` }) call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('openaigpt', 'message', script) await call('solcoder', 'solidity_answer', script)
_paq.push(['trackEvent', 'ai', 'openai', 'askFromTerminal']) _paq.push(['trackEvent', 'ai', 'solcoder', 'askFromTerminal'])
} else if (script.trim().startsWith('sol-gpt')) { } else if (script.trim().startsWith('sol-gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` }) call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('solcoder', 'solidity_answer', script) await call('solcoder', 'solidity_answer', script)

@ -54,9 +54,6 @@ const TerminalWelcomeMessage = ({ packageJson, storage }) => {
ethers.js ethers.js
</a>{' '} </a>{' '}
</li> </li>
<li key="gpt">
gpt <i>&lt;your question here&gt;</i> {' '}
</li>
<li key="sol-gpt"> <li key="sol-gpt">
sol-gpt <i>&lt;your Solidity question here&gt;</i> {' '} sol-gpt <i>&lt;your Solidity question here&gt;</i> {' '}
</li> </li>

Loading…
Cancel
Save