Skip to content

Commit 2af7a74

Browse files
committed
Add new input fields for API options and error messages
1 parent c46df6f commit 2af7a74

File tree

10 files changed

+252
-75
lines changed

10 files changed

+252
-75
lines changed

_locales/en/messages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@
132132
"perplexityTrademarkLabel": {
133133
"message": "Perplexity AI is a trademark of Perplexity AI, Inc.",
134134
"description": "Label for the Perplexity AI trademark."
135+
},
136+
"errorFrequencyPresence": {
137+
"message": "frequencyPenalty and presencePenalty are mutually exclusive.",
138+
"description": "Error message when frequency and presence are not between 0 and 1."
139+
},
140+
"errorTopkTopp": {
141+
"message": "topK and topP are mutually exclusive.",
142+
"description": "Error message when topK and topP are not between 0 and 1."
135143
}
136144

137145
}

_locales/es/messages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,13 @@
132132
"perplexityTrademarkLabel": {
133133
"message": "Perplexity AI es una marca registrada de Perplexity Inc.",
134134
"description": "Etiqueta de marca registrada para Perplexity AI."
135+
},
136+
"errorFrequencyPresence": {
137+
"message": "frequencyPenalty y presencePenalty son mutuamente exclusivos.",
138+
"description": "Mensaje de error para la frecuencia de presencia de la palabra clave."
139+
},
140+
"errorTopkTopp": {
141+
"message": "topK y topP son mutuamente exclusivos.",
142+
"description": "Mensaje de error para topK y topP."
135143
}
136144
}

_locales/fr/messages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,13 @@
132132
"perplexityTrademarkLabel": {
133133
"message": "Perplexity AI est une marque déposée de Perplexity Inc.",
134134
"description": "Libellé pour la marque Perplexity AI."
135+
},
136+
"errorFrequencyPresence": {
137+
"message": "frequencyPenalty et presencePenalty ne peuvent pas être définis en même temps.",
138+
"description": "Message d'erreur pour la fréquence de mots-clés."
139+
},
140+
"errorTopkTopp": {
141+
"message": "top_k et top_p ne peuvent pas être définis en même temps.",
142+
"description": "Message d'erreur pour top_k et top_p."
135143
}
136144
}

background/background.js

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,64 @@
88
* Call the Perplexity API with the provided parameters.
99
* Return a promise that resolves with the API response.
1010
*/
11-
function callPerplexityAPI(apiKey, model, temperature, content, language) {
11+
function callPerplexityAPI(apiKey, model, temperature, topk, topp, frequencyPenalty, presencePenalty, maxTokens, content, language) {
1212
const systemPrompt = `You are an AI assistant that generates concise, high-quality abstracts and keywords for webpage content.
1313
14-
Instructions:
15-
1. Analyze the provided webpage text and identify the main topics, key points and overall meaning. Take account of the language of the webpage. The ISO code of the language should be detected and if it is not it will be '${language}'.
16-
2. Generate an abstract in the SAME LANGUAGE as the webpage content. This is crucial. If the webpage is in Spanish, the abstract MUST be in Spanish. If the webpage is in French, the abstract MUST be in French, and so on.
17-
3. The abstract should:
18-
- Accurately and concisely summarize the key information in 1-2 paragraphs
19-
- Be well-written, precise and easy to understand
20-
- Contain the most important points without extraneous details
21-
- Be formatted as 1-2 easily readable paragraphs of plain text, each formatted as <p class="abstractp">{paragraph text}</p> WITHOUT MARKDOWN OR SPECIAL CHARACTERS
22-
4. Extract the most relevant keywords from the text that capture the main topics and themes.
23-
5. Format the output as follows, including the abstract and keywords, the final output MUST BE a valid HTML node with NO MARKDOWN at all:
24-
<div class="abstract" lang="{ISO code of the detected language}">{abstract}</div>
25-
<div class="keywords">{foreach keyword in keywords: <span class="keyword">{keyword}</span> }</div>
26-
27-
Begin!`;
14+
Instructions:
15+
1. Analyze the provided webpage text and identify the main topics, key points and overall meaning. Take account of the language of the webpage. The ISO code of the language should be detected and if it is not it will be '${language}'.
16+
2. Generate an abstract in the SAME LANGUAGE as the webpage content. This is crucial. If the webpage is in Spanish, the abstract MUST be in Spanish. If the webpage is in French, the abstract MUST be in French, and so on.
17+
3. The abstract should:
18+
- Accurately and concisely summarize the key information in 1-2 paragraphs
19+
- Be well-written, precise and easy to understand
20+
- Contain the most important points without extraneous details
21+
- Be formatted as 1-2 easily readable paragraphs of plain text, each formatted as <p class="abstractp">{paragraph text}</p> WITHOUT MARKDOWN OR SPECIAL CHARACTERS
22+
4. Extract the most relevant keywords from the text that capture the main topics and themes.
23+
5. Format the output as follows, including the abstract and keywords, the final output MUST BE a valid HTML node with NO MARKDOWN at all:
24+
<div class="abstract" lang="{ISO code of the detected language}">{abstract}</div>
25+
<div class="keywords">{foreach keyword in keywords: <span class="keyword">{keyword}</span> }</div>
2826
27+
Begin!`;
2928

3029
// Set the options for the fetch call
31-
const options = {
30+
let options = {
3231
method: 'POST',
3332
headers: {
3433
accept: 'application/json',
3534
'content-type': 'application/json',
3635
authorization: `Bearer ${apiKey}`
37-
},
38-
body: JSON.stringify({
39-
model: model,
40-
messages: [
41-
{role: 'system', content: systemPrompt},
42-
{role: 'user', content: content}
43-
],
44-
temperature: temperature
45-
})
36+
}
4637
};
4738

39+
let body = {
40+
model: model,
41+
messages: [
42+
{role: 'system', content: systemPrompt},
43+
{role: 'user', content: content}
44+
],
45+
temperature: temperature
46+
};
47+
48+
if (topk !== null) body.top_k = topk;
49+
if (topp !== null) body.top_p = topp;
50+
if (frequencyPenalty !== null) body.frequency_penalty = frequencyPenalty;
51+
if (presencePenalty !== null) body.presence_penalty = presencePenalty;
52+
if (maxTokens !== null) body.max_tokens = maxTokens;
53+
54+
options.body = JSON.stringify(body);
55+
56+
4857
return fetch('https://api.perplexity.ai/chat/completions', options)
49-
.then(response => response.json())
50-
.catch(err => console.error(err));
58+
.then(response => response.json())
59+
.catch(err => console.error(err));
5160
}
5261

5362
// Listen for messages from the popup
5463
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
5564
if (message.type === 'CALL_API') {
56-
callPerplexityAPI(message.apiKey, message.model, message.temperature, message.content).then(response => {
65+
callPerplexityAPI(message.apiKey, message.model, message.temperature, message.topk, message.topp, message.frequencyPenalty, message.presencePenalty, message.maxTokens, message.content).then(response => {
5766
sendResponse({data: response});
5867
});
5968
return true; // Return true to indicate async response
6069
}
6170
});
71+

options/options.css

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,23 @@ input[type="number"] {
4444
border-radius: 4px;
4545
margin-bottom: 10px;
4646
}
47-
/* Light Mode */
47+
48+
.input-row {
49+
display: flex;
50+
justify-content: space-between;
51+
margin-bottom: 8px;
52+
}
53+
54+
.input-group {
55+
width: 48%;
56+
}
57+
58+
.button-row {
59+
display: flex;
60+
justify-content: flex-end;
61+
margin-top: 16px;
62+
}
63+
4864
select {
4965
width: 100%;
5066
padding: 8px;

options/options.html

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,58 @@
99
<fieldset role="group" aria-labelledby="api-settings">
1010
<legend id="api-settings"></legend>
1111
<label for="apiKey" id="apiKeyLabel"></label>
12-
<input type="password" id="apiKey" name="apiKey" value="pplx-xxxxxxxxxxx" aria-required="true"><br><br>
13-
<label for="model" id="modelLabel"></label>
14-
<select id="model" name="model" aria-required="true">
15-
<optgroup label="Perplexity Models">
16-
<option value="sonar-small-chat">sonar-small-chat (7B)</option>
17-
<option value="sonar-small-online">sonar-small-online (7B)</option>
18-
<option value="sonar-medium-chat" selected>sonar-medium-chat (8x7B)</option>
19-
<option value="sonar-medium-online">sonar-medium-online (8x7B)</option>
20-
</optgroup>
21-
<optgroup label="Open-Source Models">
22-
<option value="codellama-70b-instruct">codellama-70b-instruct (70B)</option>
23-
<option value="mistral-7b-instruct">mistral-7b-instruct (7B)</option>
24-
<option value="mixtral-8x7b-instruct">mixtral-8x7b-instruct (8x7B)</option>
25-
</optgroup>
26-
</select>
27-
<br><br>
28-
<label for="temperature" id="tempLabel"></label>
29-
<input type="number" id="temperature" name="temperature" value="1" step="0.01" min="0" max="2" aria-required="true"><br><br>
30-
<button type="submit" class="ok" id="save">
31-
<span class="button-text"></span>
32-
<img src="save.svg" width="40" height="40" id="saveImg"/>
33-
</button>
12+
<input type="password" id="apiKey" name="apiKey" value="pplx-xxxxxxxxxxx" aria-required="true"><br>
13+
<label for="model" id="modelLabel"></label>
14+
<select id="model" name="model" aria-required="true">
15+
<optgroup label="Perplexity Models">
16+
<option value="sonar-small-chat">sonar-small-chat (7B)</option>
17+
<option value="sonar-small-online">sonar-small-online (7B)</option>
18+
<option value="sonar-medium-chat" selected>sonar-medium-chat (8x7B)</option>
19+
<option value="sonar-medium-online">sonar-medium-online (8x7B)</option>
20+
</optgroup>
21+
<optgroup label="Open-Source Models">
22+
<option value="codellama-70b-instruct">codellama-70b-instruct (70B)</option>
23+
<option value="mistral-7b-instruct">mistral-7b-instruct (7B)</option>
24+
<option value="mixtral-8x7b-instruct">mixtral-8x7b-instruct (8x7B)</option>
25+
</optgroup>
26+
</select>
27+
28+
<div class="input-row">
29+
<div class="input-group">
30+
<label for="temperature" id="tempLabel"></label>
31+
<input type="number" id="temperature" name="temperature" value="1" step="0.01" min="0" max="2" aria-required="true">
32+
</div>
33+
<div class="input-group">
34+
<label for="maxTokens" id="maxTokensLabel">Max Tokens</label>
35+
<input type="number" id="maxTokens" name="maxTokens" value="" step="1" min="1" max="2048" aria-required="true">
36+
</div>
37+
</div>
38+
<div class="input-row">
39+
<div class="input-group">
40+
<label for="topP" id="topPLabel">Top-p</label>
41+
<input type="number" id="topP" name="topP" value="" step="0.01" min="0" max="1" aria-required="true">
42+
</div>
43+
<div class="input-group">
44+
<label for="topK" id="topKLabel">Top-k</label>
45+
<input type="number" id="topK" name="topK" value="" step="1" min="1" max="2048" aria-required="true">
46+
</div>
47+
</div>
48+
<div class="input-row">
49+
<div class="input-group">
50+
<label for="frequencyPenalty" id="frequencyPenaltyLabel">Frequency penalty</label>
51+
<input type="number" id="frequencyPenalty" name="frequencyPenalty" value="" step="0.1" min="-2" max="2" aria-required="true">
52+
</div>
53+
<div class="input-group">
54+
<label for="presencePenalty" id="presencePenaltyLabel">Presence penalty</label>
55+
<input type="number" id="presencePenalty" name="presencePenalty" value="" step="0.1" min="0" max="2" aria-required="true">
56+
</div>
57+
</div>
58+
<div class="button-row">
59+
<button type="submit" class="ok" id="save">
60+
<span class="button-text"></span>
61+
<img src="save.svg" alt="Save icon" width="20" height="20" id="saveImg"/>
62+
</button>
63+
</div>
3464
</fieldset>
3565
</form>
3666

options/options.js

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,60 @@
1212

1313
function saveOptions(e) {
1414
e.preventDefault(); // Prevent the form from submitting normally
15+
16+
const topk = parseFloatOrDefault(document.querySelector("#topK").value);
17+
const topp = parseFloatOrDefault(document.querySelector("#topP").value);
18+
const frequencyPenalty = parseFloatOrDefault(document.querySelector("#frequencyPenalty").value);
19+
const presencePenalty = parseFloatOrDefault(document.querySelector("#presencePenalty").value);
20+
21+
if (topk !== null && topp !== null) {
22+
console.error("Error: topk and topp are mutually exclusive. Please only set one of them.");
23+
showErrorBadge(browser.i18n.getMessage('errorTopkTopp'));
24+
return;
25+
}
26+
if (frequencyPenalty !== null && presencePenalty !== null) {
27+
console.error("Error: frequencyPenalty and presencePenalty are mutually exclusive. Please only set one of them.");
28+
showErrorBadge(browser.i18n.getMessage('errorFrequencyPresence'))
29+
return;
30+
}
31+
1532
browser.storage.local.set({
1633
apiKey: document.querySelector("#apiKey").value,
1734
model: document.querySelector("#model").value,
18-
temperature: parseFloat(document.querySelector("#temperature").value)
35+
temperature: parseFloatOrDefault(document.querySelector("#temperature").value),
36+
topk: topk,
37+
topp: topp,
38+
frequencyPenalty: frequencyPenalty,
39+
presencePenalty: presencePenalty,
40+
maxTokens: parseFloatOrDefault(document.querySelector("#maxTokens").value),
1941
}).then(() => {
2042
console.log("Settings saved");
2143
showInfoBadge();
2244
}, (error) => {
2345
console.error(`Error saving settings: ${error}`);
24-
showErrorBadge();
46+
showErrorBadge(`Error saving settings: ${error}`);
2547
});
2648
}
2749

50+
function showErrorBadge(message) {
51+
const errorBadge = document.getElementById('saveError');
52+
if (errorBadge) {
53+
errorBadge.textContent = message || browser.i18n.getMessage('saveErrorMessage');
54+
errorBadge.style.opacity = '1';
55+
setTimeout(() => {
56+
errorBadge.style.opacity = '0';
57+
setTimeout(() => errorBadge.remove(), 500);
58+
}, 2000);
59+
}
60+
}
61+
62+
63+
function parseFloatOrDefault(value) {
64+
const parsedValue = parseFloat(value);
65+
return isNaN(parsedValue) ? null : parsedValue;
66+
}
67+
68+
2869
function showInfoBadge() {
2970
const infoBadge = document.getElementById('saveSuccess');
3071
if (infoBadge) {
@@ -37,17 +78,6 @@ function showInfoBadge() {
3778
}
3879
}
3980

40-
function showErrorBadge() {
41-
const errorBadge = document.getElementById('saveError');
42-
if (errorBadge) {
43-
errorBadge.textContent = browser.i18n.getMessage('saveErrorMessage');
44-
errorBadge.style.opacity = '1';
45-
setTimeout(() => {
46-
errorBadge.style.opacity = '0';
47-
setTimeout(() => errorBadge.remove(), 500);
48-
}, 2000);
49-
}
50-
}
5181

5282
/**
5383
* Restore the options to their saved state
@@ -60,6 +90,11 @@ function restoreOptions() {
6090
document.querySelector("#apiKey").value = result.apiKey || 'pplx-xxxxxxxxxxx';
6191
document.querySelector("#model").value = result.model || 'sonar-medium-chat';
6292
document.querySelector("#temperature").value = result.temperature || 1;
93+
document.querySelector("#topK").value = result.topk || '';
94+
document.querySelector("#topP").value = result.topp || '';
95+
document.querySelector("#frequencyPenalty").value = result.frequencyPenalty || '';
96+
document.querySelector("#presencePenalty").value = result.presencePenalty || '';
97+
document.querySelector("#maxTokens").value = result.maxTokens || '';
6398
}
6499

65100
/**
@@ -72,7 +107,7 @@ function restoreOptions() {
72107
console.log(browser.i18n.getMessage('errorLabel') + `: ${error}`);
73108
}
74109

75-
let getting = browser.storage.local.get(["apiKey", "model", "temperature"]);
110+
let getting = browser.storage.local.get(["apiKey", "model", "temperature", "topk", "topp", "frequencyPenalty", "presencePenalty", "maxTokens"]);
76111
getting.then(setCurrentChoice, onError);
77112
}
78113

0 commit comments

Comments
 (0)