diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts index e094677026..6c474fa8ba 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts @@ -31,6 +31,7 @@ export class CopilotSuggestion extends Plugin { this.service.events.on('done', (data) => { }) this.service.events.on('ready', (data) => { + this.emit('ready', data) this.ready = true }) } diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js index 04b77ba634..0623b3712f 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js @@ -22,7 +22,6 @@ class CodeCompletionPipeline { // Listen for messages from the main thread self.addEventListener('message', async (event) => { - console.log("worker message ", event.data) const { id, model, text, max_new_tokens, cmd, diff --git a/apps/remix-ide/src/app/plugins/solcoderAI.tsx b/apps/remix-ide/src/app/plugins/solcoderAI.tsx index aa99c74f3a..cdf2af2f1b 100644 --- a/apps/remix-ide/src/app/plugins/solcoderAI.tsx +++ b/apps/remix-ide/src/app/plugins/solcoderAI.tsx @@ -35,7 +35,7 @@ export class SolCoder extends Plugin { body: JSON.stringify({"data":[prompt, "code_generation", false,1000,0.2,0.8,50]}), }) ).json() - return result.data[0] + return "error" in result? result.error : result.data[0] } catch (e) { this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) return @@ -91,7 +91,7 @@ export class SolCoder extends Plugin { }) ).json() if (result) { - this.call('terminal', 'log', { type: 'typewriterwarning', value: result.data[0]}) + this.call('terminal', 'log', { type: 'typewriterwarning', value: "\n"+result.data[0]}) } return result.data[0] } catch (e) { @@ -135,6 +135,12 @@ export class SolCoder extends Plugin { }) ).json() + if ("error" in result){ + console.log("error", result.error) + this.call('terminal', 'log', { type: 'typewriterwarning', value: result.error }) + return result + } + return result.data } catch (e) { this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) diff --git a/apps/remix-ide/src/app/tabs/settings-tab.tsx b/apps/remix-ide/src/app/tabs/settings-tab.tsx index 7954bf5d36..61710675af 100644 --- a/apps/remix-ide/src/app/tabs/settings-tab.tsx +++ b/apps/remix-ide/src/app/tabs/settings-tab.tsx @@ -62,8 +62,7 @@ module.exports = class SettingsTab extends ViewPlugin { onActivation(): void { this.on('copilot-suggestion', 'loading', (data) => { - this.call('terminal', 'log', { type: 'typewritererror', value: `.` }) - console.log("oninit") + this.call('terminal', 'log', {type: 'typewriterlog', value: `loading Solidity copilot: ${(data.loaded / data.total) * 100}%.` }) }) } render() { diff --git a/apps/remixdesktop/src/menus/view.ts b/apps/remixdesktop/src/menus/view.ts deleted file mode 100644 index e488cfa50e..0000000000 --- a/apps/remixdesktop/src/menus/view.ts +++ /dev/null @@ -1,90 +0,0 @@ -import {BrowserWindow, MenuItemConstructorOptions} from 'electron'; - -export default ( - commandKeys: Record, - execCommand: (command: string, focusedWindow?: BrowserWindow) => void -): MenuItemConstructorOptions => { - const isMac = process.platform === 'darwin'; - - return { - label: 'View', - submenu: [ - { - label: 'Toggle Developer Tools', - accelerator: (function() { - if (process.platform === 'darwin') - return 'Alt+Command+I'; - else - return 'Ctrl+Shift+I'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.webContents.toggleDevTools(); - } - }, - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.reload(); - } - }, - { - label: 'Toggle Full Screen', - accelerator: (function() { - if (process.platform === 'darwin') - - return 'Ctrl+Command+F'; - else - return 'F11'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); - } - }, - { - label: 'Zoom In', - accelerator: 'CmdOrCtrl+=', - click: function(item, focusedWindow) { - if (focusedWindow){ - let factor = focusedWindow.webContents.getZoomFactor() - if (factor < 4) { - factor = factor + 0.25 - focusedWindow.webContents.setZoomFactor(factor) - } - } - } - }, - { - label: 'Zoom Out', - accelerator: 'CmdOrCtrl+-', - click: function(item, focusedWindow) { - if (focusedWindow){ - let factor = focusedWindow.webContents.getZoomFactor() - console.log(factor) - if (factor > 1.25) { - factor = factor - 0.25 - focusedWindow.webContents.setZoomFactor(factor) - }else{ - focusedWindow.webContents.setZoomFactor(1) - } - - } - } - }, - { - label: 'Reset Zoom', - accelerator: 'CmdOrCtrl+0', - click: function(item, focusedWindow) { - if (focusedWindow) - { - focusedWindow.webContents.setZoomFactor(1) - } - } - }, - - ] - }; -}; diff --git a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts index 9944f29ec4..1090c7c5d5 100644 --- a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts +++ b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts @@ -11,11 +11,9 @@ const result: string = '' export class RemixInLineCompletionProvider implements monacoTypes.languages.InlineCompletionsProvider { props: EditorUIProps monaco: any - running:boolean constructor(props: any, monaco: any) { this.props = props this.monaco = monaco - this.running = false } async provideInlineCompletions(model: monacoTypes.editor.ITextModel, position: monacoTypes.Position, context: monacoTypes.languages.InlineCompletionContext, token: monacoTypes.CancellationToken): Promise> { @@ -49,24 +47,26 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli 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('///') && (!this.running)) { + if (split[split.length - 1].trim() === '' && ask.startsWith('///')) { // use the code generation model, only take max 1000 word as context - this.running = true + this.props.plugin.call('terminal', 'log', {type: 'typewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '')}) + const data = await this.props.plugin.call('solcoder', 'code_completion', word) + if ("error" in data) return + console.log("solcoder completion data", data) const parsedData = data[0].trimStart() //JSON.parse(data).trimStart() const item: monacoTypes.languages.InlineCompletion = { insertText: parsedData }; - this.running =false return { items: [item], enableForwardStability: true } } } catch (e) { - console.error(e) - } + return + } if (word.split('\n').at(-1).trimStart().startsWith('//') || word.split('\n').at(-1).trimStart().startsWith('/*') || @@ -84,38 +84,47 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli let result try { - if (!this.running){ - result = await this.props.plugin.call('copilot-suggestion', 'suggest', word) - this.running = true + result = await this.props.plugin.call('copilot-suggestion', 'suggest', word) + const generatedText = (result as any).output[0].generated_text as string + let clean = generatedText + if (generatedText.indexOf('@custom:dev-run-script./') !== -1) { + clean = generatedText.replace('@custom:dev-run-script', '@custom:dev-run-script ') + } + clean = clean.replace(word, '') + clean = this.process_completion(clean) + + const item: monacoTypes.languages.InlineCompletion = { + insertText: clean + }; + return { + items: [item], + enableForwardStability: true } } catch (err) { - this.running=false return } + } - const generatedText = (result as any).output[0].generated_text as string - let clean = generatedText - console.log('solcoder inline data:\n', clean) - if (generatedText.indexOf('@custom:dev-run-script./') !== -1) { - clean = generatedText.replace('@custom:dev-run-script', '@custom:dev-run-script ') - } - clean = clean.replace(word, '') - - const item: monacoTypes.languages.InlineCompletion = { - insertText: clean - }; - this.running=false + process_completion(data: any) { + const lines = data.split('\n') + const result = [] + let incode = 0 + for (const line of lines){ + if (line.includes('{')) incode += 1 + if (line.includes('}')) incode -= 1 + + if (!line.includes('//') || !line.endsWith('}')) result.push(line) + if (incode === 0) { + return result.join('\n').trimStart() + } - // abort if there is a signal - if (token.isCancellationRequested) { - return - } - return { - items: [item], - enableForwardStability: true + if (incode <= 0 && line.includes('}')) { + return result.join('\n').trimStart() + } } - + return result.join('\n').trimStart() } + handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void { } diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index aeaa5f8b22..db7e810eb7 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -4,11 +4,6 @@ import React, {useState, useRef, useReducer, useEffect, useCallback} from 'react import {AppModal, AlertModal, ModalTypes} from '@remix-ui/app' import {labels, textDark, textSecondary} from './constants' -enum CONSENT { - GIVEN = 0, - NOT_GIVEN, - NOT_ASKED -} import './remix-ui-settings.css' import { @@ -62,7 +57,6 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { const [ipfsProjectSecret, setipfsProjectSecret] = useState('') const copilotDownload = useRef(null) - let consentGivenForAI = CONSENT.NOT_ASKED const intl = useIntl() const initValue = () => { const metadataConfig = props.config.get('settings/generate-contract-metadata') @@ -129,15 +123,6 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch) }, [props.useMatomoAnalytics]) - useEffect(() => { - console.log("useEffect on useCopilot") - if (props.useCopilot !== null) copilotActivate(props.config, props.useCopilot, dispatch) - if (props.useCopilot) { - onchangeCopilotActivate() - } - console.log("useEffect on useCopilot finish") - }, [props.useCopilot]) - const onchangeGenerateContractMetadata = (event) => { generateContractMetadat(props.config, event.target.checked, dispatch) } @@ -147,70 +132,40 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { } const onchangeCopilotActivate = () => { - console.log("onchangeCopilotActivate ", props.useCopilot) if (!props.useCopilot) { copilotActivate(props.config, props.useCopilot, dispatch) props.plugin.call('copilot-suggestion', 'uninstall') + props.plugin.call('terminal', 'log', {type: 'typewriterlog', value: `Solidity copilot deactivated` }) return } - const message =
Please wait while the copilot is downloaded. 0/100 .
props.plugin.on('copilot-suggestion', 'loading', (data) => { - if (!copilotDownload.current) return - const loaded = ((data.loaded / data.total) * 100).toString() - const dot = loaded.match(/(.*)\./g) - copilotDownload.current.innerText = dot ? dot[0].replace('.', '') : loaded + props.plugin.call('terminal', 'log', {type: 'typewriterlog', value: `loading Solidity copilot: ${(data.loaded / data.total) * 100}% done.` }) }) const startCopilot = async () => { await props.plugin.call('copilot-suggestion', 'init') - props.plugin.off('copilot-suggestion', 'loading') if (await props.plugin.call('copilot-suggestion', 'status')) { copilotActivate(props.config, true, dispatch) - } else { - props.plugin.call('copilot-suggestion', 'uninstall') - copilotActivate(props.config, false, dispatch) - } - } - const modalActivate: AppModal = { - id: 'loadcopilotActivate', - title: 'Download Solidity copilot', - modalType: ModalTypes.default, - okLabel: 'Hide', - cancelLabel: 'Cancel', - message, - okFn: async() => { - consentGivenForAI = CONSENT.GIVEN - startCopilot() - }, - hideFn: async () => { - consentGivenForAI = CONSENT.NOT_GIVEN - props.plugin.off('copilot-suggestion', 'loading') - // if (await props.plugin.call('copilot-suggestion', 'status')) { - // copilotActivate(props.config, true, dispatch) - // } else { - // props.plugin.call('copilot-suggestion', 'uninstall') - // copilotActivate(props.config, false, dispatch) - // } - } - } - - if (consentGivenForAI === CONSENT.NOT_ASKED) { - console.log("CONSENT.NOT_ASKED modal") - props.plugin.call('notification', 'modal', modalActivate) - } else if (consentGivenForAI === CONSENT.GIVEN) { - startCopilot() - } else { - // NOT_GIVEN + } } + props.plugin.on('copilot-suggestion', 'ready', (data) => { + copilotActivate(props.config, true, dispatch) + props.plugin.call('terminal', 'log', {type: 'typewriterlog', value: `Solidity Copilot activated` }) + }) + if (props.plugin.call('copilot-suggestion', 'status')) { copilotActivate(props.config, true, dispatch) } else { - props.plugin.call('copilot-suggestion', 'uninstall') - copilotActivate(props.config, false, dispatch) + startCopilot() } } + useEffect(() => { + if (props.useCopilot !== null) copilotActivate(props.config, props.useCopilot, dispatch) + onchangeCopilotActivate() + }, [props.useCopilot]) + const onchangeCopilotMaxNewToken = (event) => { copilotMaxNewToken(props.config, parseInt(event.target.value), dispatch) } @@ -482,8 +437,8 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { } let copilotTemperatureValue = (props.config.get('settings/copilot/suggest/temperature')) * 100 if (!copilotTemperatureValue) { - props.config.set('settings/copilot/suggest/temperature', 0.5) - copilotTemperatureValue = 0.5 + props.config.set('settings/copilot/suggest/temperature', 0.9) + copilotTemperatureValue = 0.9 } //if (isCopilotActivated) props.plugin.call('copilot-suggestion', 'init')