14 Commits
1.3.1 ... main

Author SHA1 Message Date
rigoni
e1618679eb add mildstone 2024-11-21 12:43:01 +01:00
Achiya Elyasaf
42960a01a2 Update service-worker.js 2024-10-20 20:52:09 +03:00
Achiya Elyasaf
3a09eb1432 Update popup.js 2024-10-20 20:51:49 +03:00
Achiya Elyasaf
261a34484c Update service-worker.js 2024-10-20 20:49:51 +03:00
Achiya Elyasaf
32b11efa1a Update popup.js 2024-10-20 20:49:11 +03:00
Achiya Elyasaf
d3bcccf4b2 Fix #9 2024-07-23 18:26:41 +03:00
Achiya Elyasaf
d01fcafeda Update README.md 2024-03-12 23:40:13 +02:00
Achiya Elyasaf
0af4246751 Update README.md 2024-03-12 23:39:35 +02:00
Achiya Elyasaf
f5228daeeb Update README.md 2023-12-07 22:09:59 +02:00
Achiya Elyasaf
1938c03a7a Update README.md 2023-12-07 22:01:57 +02:00
Achiya Elyasaf
d61da20c03 Fixed README.md markdown errors. 2023-12-07 08:48:55 +02:00
Achiya Elyasaf
f054228c6b Added explanation to the new configuration to the README.md 2023-12-06 15:50:59 +02:00
Achiya Elyasaf
def21b1450 Added the ability to change the config for each command.
Closes #1
2023-12-06 15:47:12 +02:00
Achiya Elyasaf
8fe42a658a Improved error handling 2023-12-06 08:33:41 +02:00
8 changed files with 349 additions and 98 deletions

View File

@@ -15,7 +15,13 @@ Just go to the [extension's page](https://chrome.google.com/webstore/detail/leaf
4. Click "Load unpacked" and select the repository folder 4. Click "Load unpacked" and select the repository folder
## Configuration ## Configuration
The plugin can be configured by clicking the plugin button in the Chrome toolbar. It requires inserting an API key from [OpenAI](https://platform.openai.com/account/api-keys). You also need to choose which tools you wish to enable. The plugin can be configured by clicking the plugin button in the Chrome toolbar.
It requires inserting an API key from [OpenAI](https://platform.openai.com/account/api-keys).
You also need to choose which tools you wish to enable. See the [Issues](#issues) section if you have problems activating the tools.
Change shortcuts: `chrome://extensions/shortcuts`
## Usage ## Usage
These are the tools that are currently available: These are the tools that are currently available:
@@ -29,7 +35,7 @@ Select a text and press `Alt+I` to trigger the improvement tool. The original te
### Ask ### Ask
Select a text and press `Alt+A` to trigger the ask tool. The original text will be deleted and the answer will be inserted in its place. Select a text and press `Alt+A` to trigger the ask tool. The original text will be deleted and the answer will be inserted in its place.
For example: "Create a table 4x3 that the first row is bold face" will be replaced with, e.g.,: For example: "Create a table 4x3 that the first row is boldface" will be replaced with, e.g.:
```latex ```latex
\begin{tabular}{|c|c|c|} \begin{tabular}{|c|c|c|}
\hline \hline
@@ -47,7 +53,7 @@ Entry 7 & Entry 8 & Entry 9\\
You can then, for example: You can then, for example:
1. Write before the table: Place the following tabular inside a table environment, center it, and give the following title: "The comparison of the three approaches" 1. Write before the table: Place the following tabular inside a table environment, center it, and give the following title: "The comparison of the three approaches"
2. Select the sentence and the table 2. Select the sentence and the table
3. Press `Alt+a` to trigger the ask tool. 3. Press `Alt+A` to trigger the ask tool.
The result will be: The result will be:
```latex ```latex
@@ -68,10 +74,51 @@ Entry 7 & Entry 8 & Entry 9\\
\end{table} \end{table}
``` ```
## Using non-GPT Models
Other LLM deployments/models are supported as long as they can be accessed via OpenAI Chat Completion API. Some examples: [vLLM models](https://docs.vllm.ai/en/latest/getting_started/quickstart.html#using-openai-chat-api-with-vllm), [LLAMA models](https://github.com/c0sogi/llama-api#usage-chat-completion), and [easyLLM](https://philschmid.github.io/easyllm/examples/chat-completion-api/).
Use the plugin's JSON editor to change the URL and the model. See [Issue #8](https://github.com/bThink-BGU/LeafLLM/issues/8) for further details.
## Issues ## Issues
If nothing happens when you use the plugin, verify that the plugin's shortcuts are not in conflict with other plugins' shortcuts [here](chrome://extensions/shortcuts). If nothing happens when you use the plugin, verify that the plugin's shortcuts are not in conflict with other plugins' shortcuts. To do so, go to `chrome://extensions/shortcuts`.
If you encounter any problem/question, please open an issue in the project's repository. If you encounter any problem/question, please open an issue in the project's repository.
## Privacy ## Privacy
The plugin saves its configuration locally on the users' computer. The plugin sends the API key and the selected text to OpenAI only, and only for the purpose it was made for (i.e., completing and improving text and asking GPT questions). The plugin's authors are not responsible for what OpenAI do with this data. The plugin's authors do not collect any data from the plugin's users. The plugin saves its configuration locally on the user's computer. The plugin sends the API key and the selected text to OpenAI only, and only for the purpose it was made for (i.e., completing and improving text and asking GPT questions). The plugin's authors are not responsible for what OpenAI does with this data. The plugin's authors do not collect any data from the plugin's users.
## Advanced Configuration
If you feel advanced, you can also change the request JSON sent to OpenAI and the base URL.
To do that, go to the 'Advance Configuration' component on the configuration page. By default, the value is
```json
{
"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"
}]
}
}
}
```
Base is the default configuration which is overridden by the specific command configuration.

View File

@@ -6,7 +6,7 @@
"content_scripts": [ "content_scripts": [
{ {
"js": ["scripts/jquery.js", "scripts/content.js"], "js": ["scripts/jquery.js", "scripts/content.js"],
"matches": ["https://*.overleaf.com/project/*"] "matches": ["https://*.overleaf.com/project/*", "https://*.mildstone.org/project/*"]
} }
], ],
"description": "LLM-based tools for Overleaf", "description": "LLM-based tools for Overleaf",
@@ -18,21 +18,21 @@
"commands": { "commands": {
"Complete": { "Complete": {
"suggested_key": { "suggested_key": {
"default": "Alt+C" "default": "Ctrl + Shift + C"
}, },
"description": "Complete selected text" "description": "Completa il testo selezionato"
}, },
"Improve": { "Improve": {
"suggested_key": { "suggested_key": {
"default": "Alt+I" "default": "Ctrl + Shift + I"
}, },
"description": "Improve selected text" "description": "Migliora il testo selezionato"
}, },
"Ask": { "Ask": {
"suggested_key": { "suggested_key": {
"default": "Alt+A" "default": "Ctrl + Shift + A"
}, },
"description": "Use the selected text to ask GPT. It adds to the beginning of the selected text: 'In Latex, '" "description": "Chiedi a Chat-GPT attraverso il testo selezionato"
} }
}, },
"background": { "background": {
@@ -42,5 +42,5 @@
"manifest_version": 3, "manifest_version": 3,
"name": "LeafLLM", "name": "LeafLLM",
"homepage_url": "https://github.com/achiyae/LeafLLM", "homepage_url": "https://github.com/achiyae/LeafLLM",
"version": "1.3.1" "version": "1.4.1"
} }

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,22 +1,24 @@
<html> <html>
<head> <head>
<script src="/scripts/jquery.js"></script> <script src="/scripts/jquery.js"></script>
<script src="/popup/jsoneditor.min.js"></script>
<script src="/popup/popup.js" type="module"></script> <script src="/popup/popup.js" type="module"></script>
<link rel="stylesheet" href="/popup/popup.css"/> <link rel="stylesheet" href="/popup/popup.css"/>
<link rel="stylesheet" href="/popup/jsoneditor.min.css"/>
</head> </head>
<body> <body>
<h1 class="extension-title">LeafLLM: an AI-powered Overleaf</h1> <h1 class="extension-title">LeafLLM</h1>
<div id="controls" class="form-container"> <div id="controls" class="form-container">
<div class="control"> <div class="control">
<div class="input" id="shortcut-Improve"><span>ALT</span><span>I</span></div> <div class="input" id="shortcut-Improve"><span>Alt</span><span>I</span></div>
<div class="effect">Improve selected text.</div> <div class="effect">Improve selected text.</div>
</div> </div>
<div class="control"> <div class="control">
<div class="input" id="shortcut-Complete"><span>ALT</span><span>C</span></div> <div class="input" id="shortcut-Complete"><span>Alt</span><span>C</span></div>
<div class="effect">Complete selected text.</div> <div class="effect">Complete selected text.</div>
</div> </div>
<div class="control"> <div class="control">
<div class="input" id="shortcut-Ask"><span>ALT</span><span>A</span></div> <div class="input" id="shortcut-Ask"><span>Alt</span><span>A</span></div>
<div class="effect">Ask GPT.</div> <div class="effect">Ask GPT.</div>
</div> </div>
</div> </div>
@@ -57,5 +59,14 @@
</div> </div>
</div> </div>
<div id="message-box" class="message-box"></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> </body>
</html> </html>

View File

@@ -1,4 +1,94 @@
const apiKeyRegex = /sk-[a-zA-Z0-9]{48}/ // 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, usually used for writing academic papers. Continues the given text. No need to rewrite the given text.'
}]
},
Improve: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor, usually used for writing academic papers. Style and improves the given text.'
}]
},
Ask: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor, usually used for writing academic papers. Address the given questions/request without introduction/explanations.'
}]
}
}
}
// Changing the class here requires changing scripts/content.js
class OpenAIAPI {
constructor(apiKey) {
this.apiKey = apiKey
}
query(url, data) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('POST', url, true)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.setRequestHeader('Authorization', `Bearer ${this.apiKey}`)
xhr.onerror = function () {
reject('Failed to query OpenAI API: network error.')
}
xhr.onload = function () {
if (xhr.status === 200) {
let jsonResponse
try {
jsonResponse = JSON.parse(xhr.responseText)
} catch (e) {
reject('Failed to query OpenAI API, cannot parse response:\n' + e + '\n' + xhr.responseText)
return
}
if (jsonResponse.hasOwnProperty('choices')) {
resolve(jsonResponse.choices)
} else {
reject('Failed to query OpenAI API: invalid response: ' + jsonResponse)
}
} else {
reject('Failed to query OpenAI API: invalid status: ' + xhr.status + ' - ' + xhr.responseText)
}
}
xhr.send(JSON.stringify(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)
}
}
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) { function addMessage(message) {
$('#message-box').append(`<div class="message">${message}</div>`) $('#message-box').append(`<div class="message">${message}</div>`)
@@ -17,17 +107,22 @@ async function refreshStorage() {
$('#api-token-form .api-token-status').text(chrome.runtime.lastError || !openAIAPIKey ? 'not set' : 'set') $('#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) => { chrome.storage.local.get(['Improve', 'Complete', 'Ask']).then((settings) => {
Object.values(settings).forEach(setting => { Object.values(settings).forEach(setting => {
let command = commands.filter(({ name }) => name === setting.key)[0] let command = commands.filter(({ name }) => name === setting.key)[0]
if (command.shortcut !== setting.shortcut) { if (command.shortcut !== setting.shortcut) {
setting.shortcut = command.shortcut; setting.shortcut = command.shortcut
if (setting.status === 'enabled' && setting.shortcut === '') { if (setting.status === 'enabled' && setting.shortcut === '') {
setting.status = 'error' setting.status = 'error'
} }
chrome.storage.local.set({ [setting.key]: setting }); chrome.storage.local.set({ [setting.key]: setting })
} else if (setting.status === 'enabled' && setting.shortcut === '') { } else if (setting.status === 'enabled' && setting.shortcut === '') {
setting.status = 'error' setting.status = 'error'
chrome.storage.local.set({ [setting.key]: setting }) chrome.storage.local.set({ [setting.key]: setting })
@@ -36,7 +131,7 @@ async function refreshStorage() {
let bindingFailures = Object.values(settings) let bindingFailures = Object.values(settings)
.filter(({ status }) => status === 'error') .filter(({ status }) => status === 'error')
.map(({ key }) => `${key}`) .map(({ key }) => `${key}`)
.join(', '); .join(', ')
if (bindingFailures.length > 0) { 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>.`) addErrorMessage(`Could not bind the following shortcuts:\n${bindingFailures}.\nYou can set it manually at <a href="chrome://extensions/shortcuts">chrome://extensions/shortcuts</a>.`)
} }
@@ -58,16 +153,27 @@ async function handleAPITokenSet(event) {
const openAIAPIKey = input.val() const openAIAPIKey = input.val()
input.val('') input.val('')
if (!openAIAPIKey || !apiKeyRegex.test(openAIAPIKey)) { if (!openAIAPIKey) {
addErrorMessage('Invalid API Token.') addErrorMessage('Invalid API Token.')
return return
} }
try {
await validateAPIKey(openAIAPIKey)
}catch (e) {
addErrorMessage(`Failed to validate API Token. Error: ${e}`)
return
}
chrome.storage.local.set({ openAIAPIKey }) chrome.storage.local.set({ openAIAPIKey })
.then(refreshStorage) .then(refreshStorage)
.catch((error) => addErrorMessage(`Failed to remove API Token. Error: ${error}`)) .catch((error) => addErrorMessage(`Failed to remove API Token. Error: ${error}`))
} }
async function validateAPIKey(apiKey) {
const openAI = new OpenAIAPI(apiKey)
return openAI.act('Ask', 'write a random latex command. do not explain it.')
}
async function handleAPITokenClear(event) { async function handleAPITokenClear(event) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@@ -97,6 +203,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 () { $(document).ready(async function () {
$('#api-token-form .submit').on('click', handleAPITokenSet) $('#api-token-form .submit').on('click', handleAPITokenSet)
$('#api-token-form .clear').on('click', handleAPITokenClear) $('#api-token-form .clear').on('click', handleAPITokenClear)
@@ -107,8 +227,15 @@ $(document).ready(async function () {
}) })
$('body').on('click', 'a', function () { $('body').on('click', 'a', function () {
chrome.tabs.create({url: $(this).attr('href')}); chrome.tabs.create({ url: $(this).attr('href') })
return false; return false
}); })
$('#resetConfig').on('click', async function () {
jsonEditor.set(defaultConfigurations)
await saveConfig()
})
$('#saveConfig').on('click', saveConfig)
return refreshStorage() return refreshStorage()
}) })

View File

@@ -1,72 +1,48 @@
// Changing the class here requires changing popup/popup.js
class OpenAIAPI { class OpenAIAPI {
static defaultModel = 'gpt-3.5-turbo'
constructor(apiKey) { constructor(apiKey) {
this.apiKey = apiKey this.apiKey = apiKey
} }
query(endpoint, data) { query(url, data) {
return new Promise((resolve, reject) => { 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() const xhr = new XMLHttpRequest()
xhr.open('POST', url, true) xhr.open('POST', url, true)
xhr.setRequestHeader('Content-Type', 'application/json') xhr.setRequestHeader('Content-Type', 'application/json')
xhr.setRequestHeader('Authorization', `Bearer ${this.apiKey}`) xhr.setRequestHeader('Authorization', `Bearer ${this.apiKey}`)
xhr.onreadystatechange = function () { xhr.onerror = function () {
if (xhr.readyState !== 4) return reject('Failed to query OpenAI API: network error.')
if (xhr.status !== 200) return reject('Failed to query OpenAI API.') }
xhr.onload = function () {
const jsonResponse = JSON.parse(xhr.responseText) if (xhr.status === 200) {
let jsonResponse
if (!jsonResponse.choices) return reject('Failed to query OpenAI API.') try {
jsonResponse = JSON.parse(xhr.responseText)
return resolve(jsonResponse.choices) } catch (e) {
reject('Failed to query OpenAI API, cannot parse response:\n' + e + '\n' + xhr.responseText)
return
}
if (jsonResponse.hasOwnProperty('choices')) {
resolve(jsonResponse.choices)
} else {
reject('Failed to query OpenAI API: invalid response: ' + jsonResponse)
}
} else {
reject('Failed to query OpenAI API: invalid status: ' + xhr.status + ' - ' + xhr.responseText)
}
} }
xhr.send(JSON.stringify(data)) xhr.send(JSON.stringify(data))
}) })
} }
async completeText(text) { async act(command, text) {
const data = { let conf = (await chrome.storage.local.get('RequestConfiguration')).RequestConfiguration.openai
max_tokens: 512, let request = Object.assign({}, conf.base)
messages: [ let url = conf.url
{ role: 'system', content: 'You are an assistant in a Latex editor that continues the given text. No need to rewrite the given text' }, Object.assign(request, conf[command])
{ role: 'user', 'content': text } request.messages.push({ role: 'user', 'content': text })
], return this.query(url, request)
}
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)
.then(result => result[0]['message'].content) .then(result => result[0]['message'].content)
} }
} }
@@ -102,7 +78,7 @@ async function improveTextHandler(openAI) {
const selection = window.getSelection() const selection = window.getSelection()
const selectedText = selection.toString() const selectedText = selection.toString()
if (!selectedText) return if (!selectedText) return
const editedText = await openAI.improveText(selectedText) const editedText = await openAI.act('Improve', selectedText)
const commentedText = commentText(selectedText) const commentedText = commentText(selectedText)
replaceSelectedText(commentedText + '\n' + editedText, selection) replaceSelectedText(commentedText + '\n' + editedText, selection)
} }
@@ -112,7 +88,7 @@ async function completeTextHandler(openAI) {
const selection = window.getSelection() const selection = window.getSelection()
const selectedText = selection.toString() const selectedText = selection.toString()
if (!selectedText) return if (!selectedText) return
const editedText = (await openAI.completeText(selectedText)).trimStart() const editedText = (await openAI.act('Complete', selectedText)).trimStart()
replaceSelectedText(selectedText + '\n' + editedText, selection) replaceSelectedText(selectedText + '\n' + editedText, selection)
} }
@@ -121,7 +97,7 @@ async function askHandler(openAI) {
const selection = window.getSelection() const selection = window.getSelection()
const selectedText = selection.toString() const selectedText = selection.toString()
if (!selectedText) return if (!selectedText) return
const editedText = (await openAI.ask(selectedText)).trimStart() const editedText = (await openAI.act('Ask', selectedText)).trimStart()
replaceSelectedText(editedText, selection) replaceSelectedText(editedText, selection)
} }
@@ -156,10 +132,7 @@ function handleCommand(command) {
function error(msg, error) { function error(msg, error) {
if(error) { if(error) {
msg += ` Error message: ${error.message}` msg += ` Error message: ${JSON.stringify(error)}`
if(error.cause) {
console.error(`\nCause: ${JSON.stringify(error.cause)}`)
}
} }
customAlert(msg) customAlert(msg)
console.error(`LeafLLM: ${msg}`) console.error(`LeafLLM: ${msg}`)

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-4-turbo'
},
Complete: {
max_tokens: 512,
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor, usually used for writing academic papers. Continues the given text. No need to rewrite the given text.'
}]
},
Improve: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor, usually used for writing academic papers. Style and improves the given text.'
}]
},
Ask: {
messages: [{
role: 'system',
content: 'You are an assistant in a Latex editor, usually used for writing academic papers. Address the given questions/request without introduction/explanations.'
}]
}
}
}
const settings = [ const settings = [
{ key: 'Complete', shortcut: 'Alt+C', status: 'enabled', type: 'Command' }, { key: 'Complete', shortcut: 'Ctrl + Shift + C', status: 'enabled', type: 'Command' },
{ key: 'Improve', shortcut: 'Alt+I', status: 'enabled', type: 'Command' }, { key: 'Improve', shortcut: 'Ctrl + Shift + I', status: 'enabled', type: 'Command' },
{ key: 'Ask', shortcut: 'Alt+A', status: 'enabled', type: 'Command' } { key: 'Ask', shortcut: 'Ctrl + Shift + A', status: 'enabled', type: 'Command' },
{ key: 'RequestConfiguration', value: defaultConfigurations, type: 'Configuration' }
] ]
async function sendMessage(message) { async function sendMessage(message) {
@@ -42,6 +74,14 @@ async function checkCommandShortcuts() {
chrome.runtime.onInstalled.addListener((reason) => { chrome.runtime.onInstalled.addListener((reason) => {
if (reason.reason === chrome.runtime.OnInstalledReason.INSTALL) { if (reason.reason === chrome.runtime.OnInstalledReason.INSTALL) {
checkCommandShortcuts() 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 })
}
} }
}) })
@@ -49,6 +89,7 @@ async function setup() {
addListener('Improve') addListener('Improve')
addListener('Complete') addListener('Complete')
addListener('Ask') addListener('Ask')
console.log('LeafLLM service worker installed')
} }
setup() setup()