Skip to content

Commit

Permalink
Merge pull request #11 from imigueldiaz/technical-parameters
Browse files Browse the repository at this point in the history
Technical parameters
  • Loading branch information
imigueldiaz authored Apr 10, 2024
2 parents c46df6f + 1717bfa commit 1df1a71
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 76 deletions.
8 changes: 8 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@
"perplexityTrademarkLabel": {
"message": "Perplexity AI is a trademark of Perplexity AI, Inc.",
"description": "Label for the Perplexity AI trademark."
},
"errorFrequencyPresence": {
"message": "frequencyPenalty and presencePenalty are mutually exclusive.",
"description": "Error message when frequency and presence are not between 0 and 1."
},
"errorTopkTopp": {
"message": "topK and topP are mutually exclusive.",
"description": "Error message when topK and topP are not between 0 and 1."
}

}
8 changes: 8 additions & 0 deletions _locales/es/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,13 @@
"perplexityTrademarkLabel": {
"message": "Perplexity AI es una marca registrada de Perplexity Inc.",
"description": "Etiqueta de marca registrada para Perplexity AI."
},
"errorFrequencyPresence": {
"message": "frequencyPenalty y presencePenalty son mutuamente exclusivos.",
"description": "Mensaje de error para la frecuencia de presencia de la palabra clave."
},
"errorTopkTopp": {
"message": "topK y topP son mutuamente exclusivos.",
"description": "Mensaje de error para topK y topP."
}
}
8 changes: 8 additions & 0 deletions _locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,13 @@
"perplexityTrademarkLabel": {
"message": "Perplexity AI est une marque déposée de Perplexity Inc.",
"description": "Libellé pour la marque Perplexity AI."
},
"errorFrequencyPresence": {
"message": "frequencyPenalty et presencePenalty ne peuvent pas être définis en même temps.",
"description": "Message d'erreur pour la fréquence de mots-clés."
},
"errorTopkTopp": {
"message": "top_k et top_p ne peuvent pas être définis en même temps.",
"description": "Message d'erreur pour top_k et top_p."
}
}
74 changes: 45 additions & 29 deletions background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,76 @@
* @param {string} apiKey
* @param {string} model
* @param {number} temperature
* @param {number} topk
* @param {number} topp
* @param {number} frequencyPenalty
* @param {number} presencePenalty
* @param {number} maxTokens
* @param {string} content
* @param {string} language
* @returns {Promise<any>}
* Call the Perplexity API with the provided parameters.
* Return a promise that resolves with the API response.
*/
function callPerplexityAPI(apiKey, model, temperature, content, language) {
function callPerplexityAPI(apiKey, model, temperature, topk, topp, frequencyPenalty, presencePenalty, maxTokens, content, language) {
const API_ENDPOINT = 'https://api.perplexity.ai/chat/completions';
const systemPrompt = `You are an AI assistant that generates concise, high-quality abstracts and keywords for webpage content.
Instructions:
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}'.
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.
3. The abstract should:
- Accurately and concisely summarize the key information in 1-2 paragraphs
- Be well-written, precise and easy to understand
- Contain the most important points without extraneous details
- 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
4. Extract the most relevant keywords from the text that capture the main topics and themes.
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:
<div class="abstract" lang="{ISO code of the detected language}">{abstract}</div>
<div class="keywords">{foreach keyword in keywords: <span class="keyword">{keyword}</span> }</div>
Begin!`;
Instructions:
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}'.
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.
3. The abstract should:
- Accurately and concisely summarize the key information in 1-2 paragraphs
- Be well-written, precise and easy to understand
- Contain the most important points without extraneous details
- 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
4. Extract the most relevant keywords from the text that capture the main topics and themes.
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:
<div class="abstract" lang="{ISO code of the detected language}">{abstract}</div>
<div class="keywords">{foreach keyword in keywords: <span class="keyword">{keyword}</span> }</div>
Begin!`;

// Set the options for the fetch call
const options = {
let options = {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: `Bearer ${apiKey}`
},
body: JSON.stringify({
model: model,
messages: [
{role: 'system', content: systemPrompt},
{role: 'user', content: content}
],
temperature: temperature
})
}
};

return fetch('https://api.perplexity.ai/chat/completions', options)
.then(response => response.json())
.catch(err => console.error(err));
let body = {
model: model,
messages: [
{role: 'system', content: systemPrompt},
{role: 'user', content: content}
],
temperature: temperature
};

if (topk !== null) body.top_k = topk;
if (topp !== null) body.top_p = topp;
if (frequencyPenalty !== null) body.frequency_penalty = frequencyPenalty;
if (presencePenalty !== null) body.presence_penalty = presencePenalty;
if (maxTokens !== null) body.max_tokens = maxTokens;

options.body = JSON.stringify(body);


return fetch(API_ENDPOINT, options)
.then(response => response.json())
.catch(err => console.error(err));
}

// Listen for messages from the popup
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'CALL_API') {
callPerplexityAPI(message.apiKey, message.model, message.temperature, message.content).then(response => {
callPerplexityAPI(message.apiKey, message.model, message.temperature, message.topk, message.topp, message.frequencyPenalty, message.presencePenalty, message.maxTokens, message.content).then(response => {
sendResponse({data: response});
});
return true; // Return true to indicate async response
}
});

18 changes: 17 additions & 1 deletion options/options.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,23 @@ input[type="number"] {
border-radius: 4px;
margin-bottom: 10px;
}
/* Light Mode */

.input-row {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}

.input-group {
width: 48%;
}

.button-row {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}

select {
width: 100%;
padding: 8px;
Expand Down
74 changes: 52 additions & 22 deletions options/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,58 @@
<fieldset role="group" aria-labelledby="api-settings">
<legend id="api-settings"></legend>
<label for="apiKey" id="apiKeyLabel"></label>
<input type="password" id="apiKey" name="apiKey" value="pplx-xxxxxxxxxxx" aria-required="true"><br><br>
<label for="model" id="modelLabel"></label>
<select id="model" name="model" aria-required="true">
<optgroup label="Perplexity Models">
<option value="sonar-small-chat">sonar-small-chat (7B)</option>
<option value="sonar-small-online">sonar-small-online (7B)</option>
<option value="sonar-medium-chat" selected>sonar-medium-chat (8x7B)</option>
<option value="sonar-medium-online">sonar-medium-online (8x7B)</option>
</optgroup>
<optgroup label="Open-Source Models">
<option value="codellama-70b-instruct">codellama-70b-instruct (70B)</option>
<option value="mistral-7b-instruct">mistral-7b-instruct (7B)</option>
<option value="mixtral-8x7b-instruct">mixtral-8x7b-instruct (8x7B)</option>
</optgroup>
</select>
<br><br>
<label for="temperature" id="tempLabel"></label>
<input type="number" id="temperature" name="temperature" value="1" step="0.01" min="0" max="2" aria-required="true"><br><br>
<button type="submit" class="ok" id="save">
<span class="button-text"></span>
<img src="save.svg" width="40" height="40" id="saveImg"/>
</button>
<input type="password" id="apiKey" name="apiKey" value="pplx-xxxxxxxxxxx" aria-required="true"><br>
<label for="model" id="modelLabel"></label>
<select id="model" name="model" aria-required="true">
<optgroup label="Perplexity Models">
<option value="sonar-small-chat">sonar-small-chat (7B)</option>
<option value="sonar-small-online">sonar-small-online (7B)</option>
<option value="sonar-medium-chat" selected>sonar-medium-chat (8x7B)</option>
<option value="sonar-medium-online">sonar-medium-online (8x7B)</option>
</optgroup>
<optgroup label="Open-Source Models">
<option value="codellama-70b-instruct">codellama-70b-instruct (70B)</option>
<option value="mistral-7b-instruct">mistral-7b-instruct (7B)</option>
<option value="mixtral-8x7b-instruct">mixtral-8x7b-instruct (8x7B)</option>
</optgroup>
</select>

<div class="input-row">
<div class="input-group">
<label for="temperature" id="tempLabel"></label>
<input type="number" id="temperature" name="temperature" value="1" step="0.01" min="0" max="2" aria-required="true">
</div>
<div class="input-group">
<label for="maxTokens" id="maxTokensLabel">Max Tokens</label>
<input type="number" id="maxTokens" name="maxTokens" value="" step="1" min="1" max="2048" aria-required="true">
</div>
</div>
<div class="input-row">
<div class="input-group">
<label for="topP" id="topPLabel">Top-p</label>
<input type="number" id="topP" name="topP" value="" step="0.01" min="0" max="1" aria-required="true">
</div>
<div class="input-group">
<label for="topK" id="topKLabel">Top-k</label>
<input type="number" id="topK" name="topK" value="" step="1" min="1" max="2048" aria-required="true">
</div>
</div>
<div class="input-row">
<div class="input-group">
<label for="frequencyPenalty" id="frequencyPenaltyLabel">Frequency penalty</label>
<input type="number" id="frequencyPenalty" name="frequencyPenalty" value="" step="0.1" min="-2" max="2" aria-required="true">
</div>
<div class="input-group">
<label for="presencePenalty" id="presencePenaltyLabel">Presence penalty</label>
<input type="number" id="presencePenalty" name="presencePenalty" value="" step="0.1" min="0" max="2" aria-required="true">
</div>
</div>
<div class="button-row">
<button type="submit" class="ok" id="save">
<span class="button-text"></span>
<img src="save.svg" alt="Save icon" width="20" height="20" id="saveImg"/>
</button>
</div>
</fieldset>
</form>

Expand Down
63 changes: 49 additions & 14 deletions options/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,60 @@

function saveOptions(e) {
e.preventDefault(); // Prevent the form from submitting normally

const topk = parseFloatOrDefault(document.querySelector("#topK").value);
const topp = parseFloatOrDefault(document.querySelector("#topP").value);
const frequencyPenalty = parseFloatOrDefault(document.querySelector("#frequencyPenalty").value);
const presencePenalty = parseFloatOrDefault(document.querySelector("#presencePenalty").value);

if (topk !== null && topp !== null) {
console.error("Error: topk and topp are mutually exclusive. Please only set one of them.");
showErrorBadge(browser.i18n.getMessage('errorTopkTopp'));
return;
}
if (frequencyPenalty !== null && presencePenalty !== null) {
console.error("Error: frequencyPenalty and presencePenalty are mutually exclusive. Please only set one of them.");
showErrorBadge(browser.i18n.getMessage('errorFrequencyPresence'))
return;
}

browser.storage.local.set({
apiKey: document.querySelector("#apiKey").value,
model: document.querySelector("#model").value,
temperature: parseFloat(document.querySelector("#temperature").value)
temperature: parseFloatOrDefault(document.querySelector("#temperature").value),
topk: topk,
topp: topp,
frequencyPenalty: frequencyPenalty,
presencePenalty: presencePenalty,
maxTokens: parseFloatOrDefault(document.querySelector("#maxTokens").value),
}).then(() => {
console.log("Settings saved");
showInfoBadge();
}, (error) => {
console.error(`Error saving settings: ${error}`);
showErrorBadge();
showErrorBadge(`Error saving settings: ${error}`);
});
}

function showErrorBadge(message) {
const errorBadge = document.getElementById('saveError');
if (errorBadge) {
errorBadge.textContent = message || browser.i18n.getMessage('saveErrorMessage');
errorBadge.style.opacity = '1';
setTimeout(() => {
errorBadge.style.opacity = '0';
setTimeout(() => errorBadge.remove(), 500);
}, 2000);
}
}


function parseFloatOrDefault(value) {
const parsedValue = parseFloat(value);
return isNaN(parsedValue) ? null : parsedValue;
}


function showInfoBadge() {
const infoBadge = document.getElementById('saveSuccess');
if (infoBadge) {
Expand All @@ -37,17 +78,6 @@ function showInfoBadge() {
}
}

function showErrorBadge() {
const errorBadge = document.getElementById('saveError');
if (errorBadge) {
errorBadge.textContent = browser.i18n.getMessage('saveErrorMessage');
errorBadge.style.opacity = '1';
setTimeout(() => {
errorBadge.style.opacity = '0';
setTimeout(() => errorBadge.remove(), 500);
}, 2000);
}
}

/**
* Restore the options to their saved state
Expand All @@ -60,6 +90,11 @@ function restoreOptions() {
document.querySelector("#apiKey").value = result.apiKey || 'pplx-xxxxxxxxxxx';
document.querySelector("#model").value = result.model || 'sonar-medium-chat';
document.querySelector("#temperature").value = result.temperature || 1;
document.querySelector("#topK").value = result.topk || '';
document.querySelector("#topP").value = result.topp || '';
document.querySelector("#frequencyPenalty").value = result.frequencyPenalty || '';
document.querySelector("#presencePenalty").value = result.presencePenalty || '';
document.querySelector("#maxTokens").value = result.maxTokens || '';
}

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

let getting = browser.storage.local.get(["apiKey", "model", "temperature"]);
let getting = browser.storage.local.get(["apiKey", "model", "temperature", "topk", "topp", "frequencyPenalty", "presencePenalty", "maxTokens"]);
getting.then(setCurrentChoice, onError);
}

Expand Down
Loading

0 comments on commit 1df1a71

Please sign in to comment.