Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3bcccf4b2 | ||
|
|
d01fcafeda | ||
|
|
0af4246751 | ||
|
|
f5228daeeb | ||
|
|
1938c03a7a | ||
|
|
d61da20c03 |
88
README.md
88
README.md
@@ -15,42 +15,11 @@ Just go to the [extension's page](https://chrome.google.com/webstore/detail/leaf
|
||||
4. Click "Load unpacked" and select the repository folder
|
||||
|
||||
## 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.
|
||||
|
||||
If you feel advanced, you can also change the request JSON sent to OpenAI and also the base URL.
|
||||
To do that, go to the 'Advance Configuration' component in 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.
|
||||
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.
|
||||
|
||||
## Usage
|
||||
These are the tools that are currently available:
|
||||
@@ -64,7 +33,7 @@ Select a text and press `Alt+I` to trigger the improvement tool. The original te
|
||||
### 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.
|
||||
|
||||
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
|
||||
\begin{tabular}{|c|c|c|}
|
||||
\hline
|
||||
@@ -82,7 +51,7 @@ Entry 7 & Entry 8 & Entry 9\\
|
||||
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"
|
||||
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:
|
||||
```latex
|
||||
@@ -103,10 +72,51 @@ Entry 7 & Entry 8 & Entry 9\\
|
||||
\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
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -42,5 +42,5 @@
|
||||
"manifest_version": 3,
|
||||
"name": "LeafLLM",
|
||||
"homepage_url": "https://github.com/achiyae/LeafLLM",
|
||||
"version": "1.4.0"
|
||||
"version": "1.4.1"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,56 @@ const defaultConfigurations = {
|
||||
}
|
||||
}
|
||||
|
||||
const apiKeyRegex = /sk-[a-zA-Z0-9]{48}/
|
||||
// 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() {
|
||||
@@ -104,16 +153,27 @@ async function handleAPITokenSet(event) {
|
||||
const openAIAPIKey = input.val()
|
||||
input.val('')
|
||||
|
||||
if (!openAIAPIKey || !apiKeyRegex.test(openAIAPIKey)) {
|
||||
if (!openAIAPIKey) {
|
||||
addErrorMessage('Invalid API Token.')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await validateAPIKey(openAIAPIKey)
|
||||
}catch (e) {
|
||||
addErrorMessage(`Failed to validate API Token. Error: ${e}`)
|
||||
return
|
||||
}
|
||||
|
||||
chrome.storage.local.set({ openAIAPIKey })
|
||||
.then(refreshStorage)
|
||||
.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) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
// Changing the class here requires changing popup/popup.js
|
||||
class OpenAIAPI {
|
||||
static defaultModel = 'gpt-3.5-turbo'
|
||||
|
||||
constructor(apiKey) {
|
||||
this.apiKey = apiKey
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user