Added the ability to change the config for each command.

Closes #1
This commit is contained in:
Achiya Elyasaf
2023-12-06 15:47:12 +02:00
parent 8fe42a658a
commit def21b1450
7 changed files with 198 additions and 61 deletions

View File

@@ -42,5 +42,5 @@
"manifest_version": 3,
"name": "LeafLLM",
"homepage_url": "https://github.com/achiyae/LeafLLM",
"version": "1.3.2"
"version": "1.4.0"
}

6
popup/jsoneditor.min.css vendored Normal file

File diff suppressed because one or more lines are too long

46
popup/jsoneditor.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,10 @@
<html>
<head>
<script src="/scripts/jquery.js"></script>
<script src="/popup/jsoneditor.min.js"></script>
<script src="/popup/popup.js" type="module"></script>
<link rel="stylesheet" href="/popup/popup.css"/>
<link rel="stylesheet" href="/popup/jsoneditor.min.css"/>
</head>
<body>
<h1 class="extension-title">LeafLLM: an AI-powered Overleaf</h1>
@@ -57,5 +59,14 @@
</div>
</div>
<div id="message-box" class="message-box"></div>
<div id="configuration-form" class="form-container">
<div class="settings-text">Advanced Configuration</div>
<!-- JSON Editor Container -->
<div id="json-editor" style="height: 300px;"></div>
<div class="btn-container">
<button class="submit btn" id="saveConfig">Save config</button>
<button class="clear btn" id="resetConfig">Reset config</button>
</div>
</div>
</body>
</html>

View File

@@ -1,4 +1,45 @@
// Changing defaultConfigurations requires changing service-worker.js
const defaultConfigurations = {
openai: {
url: 'https://api.openai.com/v1/chat/completions',
base: {
n: 1,
temperature: 0.5,
model: 'gpt-3.5-turbo'
},
Complete: {
max_tokens: 512,
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor that continues the given text. No need to rewrite the given text'
}]
},
Improve: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor that improves the given text'
}]
},
Ask: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor. Answer questions without introduction/explanations'
}]
}
}
}
const apiKeyRegex = /sk-[a-zA-Z0-9]{48}/
const jsonEditor = createJsonEditor()
function createJsonEditor() {
return new JSONEditor($('#json-editor')[0], {
mode: 'code', // Use code mode for better editing
onChange: function () {
$('#saveConfig').prop('disabled', false);
}
})
}
function addMessage(message) {
$('#message-box').append(`<div class="message">${message}</div>`)
@@ -17,18 +58,23 @@ async function refreshStorage() {
$('#api-token-form .api-token-status').text(chrome.runtime.lastError || !openAIAPIKey ? 'not set' : 'set')
})
const commands = await chrome.commands.getAll();
const commands = await chrome.commands.getAll()
chrome.storage.local.get(['RequestConfiguration']).then((settings) => {
jsonEditor.set(settings.RequestConfiguration)
$('#saveConfig').prop('disabled', true);
})
chrome.storage.local.get(['Improve', 'Complete', 'Ask']).then((settings) => {
Object.values(settings).forEach(setting => {
let command = commands.filter(({ name }) => name === setting.key)[0]
if(command.shortcut !== setting.shortcut) {
setting.shortcut = command.shortcut;
if(setting.status === 'enabled' && setting.shortcut === '') {
if (command.shortcut !== setting.shortcut) {
setting.shortcut = command.shortcut
if (setting.status === 'enabled' && setting.shortcut === '') {
setting.status = 'error'
}
chrome.storage.local.set({ [setting.key]: setting });
} else if(setting.status === 'enabled' && setting.shortcut === '') {
chrome.storage.local.set({ [setting.key]: setting })
} else if (setting.status === 'enabled' && setting.shortcut === '') {
setting.status = 'error'
chrome.storage.local.set({ [setting.key]: setting })
}
@@ -36,7 +82,7 @@ async function refreshStorage() {
let bindingFailures = Object.values(settings)
.filter(({ status }) => status === 'error')
.map(({ key }) => `${key}`)
.join(', ');
.join(', ')
if (bindingFailures.length > 0) {
addErrorMessage(`Could not bind the following shortcuts:\n${bindingFailures}.\nYou can set it manually at <a href="chrome://extensions/shortcuts">chrome://extensions/shortcuts</a>.`)
}
@@ -87,7 +133,7 @@ function makeHandleSettingChange(key) {
const value = event.target.checked
const setting = await chrome.storage.local.get(key)
/* let commandKey = await chrome.commands.getAll()
/* let commandKey = await chrome.commands.getAll()
commandKey = commandKey.filter(({ name }) => name === key)[0]*/
// if (setting[key].status !== 'error') {
setting[key].status = value ? 'enabled' : 'disabled'
@@ -97,6 +143,20 @@ function makeHandleSettingChange(key) {
}
}
async function saveConfig() {
clearMessages()
let config;
try {
config = jsonEditor.get()
} catch (e) {
addErrorMessage(`Failed to parse configuration. Error: ${e}`)
return
}
chrome.storage.local.set({ RequestConfiguration: config })
.then(refreshStorage)
.catch((error) => addErrorMessage(`Failed to save configuration. Error: ${error}`))
}
$(document).ready(async function () {
$('#api-token-form .submit').on('click', handleAPITokenSet)
$('#api-token-form .clear').on('click', handleAPITokenClear)
@@ -106,9 +166,16 @@ $(document).ready(async function () {
$(`#settings-form input[name='text-${key}']:checkbox`).on('change', makeHandleSettingChange(key))
})
$('body').on('click', 'a', function(){
chrome.tabs.create({url: $(this).attr('href')});
return false;
});
$('body').on('click', 'a', function () {
chrome.tabs.create({ url: $(this).attr('href') })
return false
})
$('#resetConfig').on('click', async function () {
jsonEditor.set(defaultConfigurations)
await saveConfig()
})
$('#saveConfig').on('click', saveConfig)
return refreshStorage()
})

View File

@@ -6,14 +6,8 @@ class OpenAIAPI {
this.apiKey = apiKey
}
query(endpoint, data) {
query(url, data) {
return new Promise((resolve, reject) => {
const url = `https://api.openai.com/v1/${endpoint}`
if (!data.model) data.model = OpenAIAPI.defaultModel
if (!data.n) data.n = 1
if (!data.temperature) data.temperature = 0.5
const xhr = new XMLHttpRequest()
xhr.open('POST', url, true)
xhr.setRequestHeader('Content-Type', 'application/json')
@@ -44,40 +38,13 @@ class OpenAIAPI {
})
}
async completeText(text) {
const data = {
max_tokens: 512,
messages: [
{ role: 'system', content: 'You are an assistant in a Latex editor that continues the given text. No need to rewrite the given text' },
{ role: 'user', 'content': text }
],
}
return this.query('chat/completions', data)
.then(result => result[0]['message'].content)
}
async improveText(text) {
const data = {
messages: [
{ role: 'system', content: 'You are an assistant in a Latex editor' },
{ role: 'user', 'content': 'Improve the following text:\n'+text }],
}
return this.query('chat/completions', data)
.then(result => result[0]['message'].content)
}
async ask(text) {
const data = {
max_tokens: 512,
messages: [
{ role: 'system', content: 'You are an assistant in a Latex editor. Answer questions without introduction/explanations' },
{ role: 'user', 'content': text }
],
}
return this.query('chat/completions', data)
async act(command, text) {
let conf = (await chrome.storage.local.get('RequestConfiguration')).RequestConfiguration.openai
let request = Object.assign({}, conf.base)
let url = conf.url
Object.assign(request, conf[command])
request.messages.push({ role: 'user', 'content': text })
return this.query(url, request)
.then(result => result[0]['message'].content)
}
}
@@ -113,7 +80,7 @@ async function improveTextHandler(openAI) {
const selection = window.getSelection()
const selectedText = selection.toString()
if (!selectedText) return
const editedText = await openAI.improveText(selectedText)
const editedText = await openAI.act('Improve', selectedText)
const commentedText = commentText(selectedText)
replaceSelectedText(commentedText + '\n' + editedText, selection)
}
@@ -123,7 +90,7 @@ async function completeTextHandler(openAI) {
const selection = window.getSelection()
const selectedText = selection.toString()
if (!selectedText) return
const editedText = (await openAI.completeText(selectedText)).trimStart()
const editedText = (await openAI.act('Complete', selectedText)).trimStart()
replaceSelectedText(selectedText + '\n' + editedText, selection)
}
@@ -132,7 +99,7 @@ async function askHandler(openAI) {
const selection = window.getSelection()
const selectedText = selection.toString()
if (!selectedText) return
const editedText = (await openAI.ask(selectedText)).trimStart()
const editedText = (await openAI.act('Ask', selectedText)).trimStart()
replaceSelectedText(editedText, selection)
}

View File

@@ -1,7 +1,39 @@
// Changing defaultConfigurations requires changing popup/popup.js
const defaultConfigurations = {
openai: {
url: 'https://api.openai.com/v1/chat/completions',
base: {
n: 1,
temperature: 0.5,
model: 'gpt-3.5-turbo'
},
Complete: {
max_tokens: 512,
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor that continues the given text. No need to rewrite the given text'
}]
},
Improve: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor that improves the given text'
}]
},
Ask: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor. Answer questions without introduction/explanations'
}]
}
}
}
const settings = [
{ key: 'Complete', shortcut: 'Alt+C', status: 'enabled', type: 'Command' },
{ key: 'Improve', shortcut: 'Alt+I', status: 'enabled', type: 'Command' },
{ key: 'Ask', shortcut: 'Alt+A', status: 'enabled', type: 'Command' }
{ key: 'Ask', shortcut: 'Alt+A', status: 'enabled', type: 'Command' },
{ key: 'RequestConfiguration', value: defaultConfigurations, type: 'Configuration' }
]
async function sendMessage(message) {
@@ -42,6 +74,14 @@ async function checkCommandShortcuts() {
chrome.runtime.onInstalled.addListener((reason) => {
if (reason.reason === chrome.runtime.OnInstalledReason.INSTALL) {
checkCommandShortcuts()
chrome.storage.local.set({ RequestConfiguration: defaultConfigurations })
} else if (reason.reason === chrome.runtime.OnInstalledReason.UPDATE) {
let newVersion = chrome.runtime.getManifest().version
let oldVersion = reason.previousVersion
let oldVersionArray = oldVersion.split('.')
if (parseInt(oldVersionArray[0]) === 1 && parseInt(oldVersionArray[1]) < 4) {
chrome.storage.local.set({ RequestConfiguration: defaultConfigurations })
}
}
})