From d3bcccf4b2875f0a23303b5241598a5dd7f0a807 Mon Sep 17 00:00:00 2001 From: Achiya Elyasaf <10044875+achiyae@users.noreply.github.com> Date: Tue, 23 Jul 2024 18:26:41 +0300 Subject: [PATCH] Fix #9 --- manifest.json | 2 +- popup/popup.js | 64 ++++++++++++++++++++++++++++++++++++++++++++-- scripts/content.js | 4 +-- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/manifest.json b/manifest.json index 887ce66..bd9c994 100644 --- a/manifest.json +++ b/manifest.json @@ -42,5 +42,5 @@ "manifest_version": 3, "name": "LeafLLM", "homepage_url": "https://github.com/achiyae/LeafLLM", - "version": "1.4.0" + "version": "1.4.1" } diff --git a/popup/popup.js b/popup/popup.js index 81b00fb..51945f4 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -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() diff --git a/scripts/content.js b/scripts/content.js index 08e1996..e61f438 100644 --- a/scripts/content.js +++ b/scripts/content.js @@ -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 }