Skip to content

Latest commit

 

History

History
161 lines (125 loc) · 8.15 KB

README.md

File metadata and controls

161 lines (125 loc) · 8.15 KB

Programmable Buttons

Twitter License: MIT

This repository contains open-source code snippets for programmable buttons in Orion browser.

Orion is modern, high performance, WebKit based, zero-telemetry browser for Apple devices.

Download Orion browser by Kagi.

Programmable Button demos

Usage:

  • Right click and copy the link to the button.
  • Right click Orion toolbar and select "Import Button from URL".

Browser interaction buttons

AI buttons

You will need to input your OpenAI API key in the code for these to work. When you import the button, right click it, select edit, switch to code, and then replace OpenAI API key on the top of the code.

  • Unbiased News: Uses OpenAI API to produce unbiased rewrite of the news article. Make sure to replace apiKey in the code after importing.
  • Summarize: Uses OpenAI API to produce summary of the page. Make sure to replace apiKey in the code after importing. This is just a proof of concept and will not work with all pages. For a more robust summarization API, consider using Universal Summarizer.
  • Stock Analysis: Uses OpenAI API to produce stock analysis based on the content of the page. Works best on financial sites like seekingalpha.com. Make sure to replace apiKey in the code after importing.

Community Buttons

Community members are welcome to contribute their own programmable buttons in the Community Buttons folder.

Currently available are:

Demo

Cick the thumbnail to watch the video.

Watch the video

Pro tip

You can inspect the code, icons and options used in the button by converting the file into a more readable format like xml.

For example:

plutil -convert xml1 -o Summarize.xml Summarize.plist

Example

External API call

The code will call an external API and display result in Orion sidebar.

    (async () => {
        const apiKey = 'your_api_key';
        const text = document.title + ' ' + Array.from(document.querySelectorAll('p')).map(p => p.innerText).join(' ');
        const requestBody = {
            'model': 'gpt-3.5-turbo',
            'messages': [
                { 'role': 'system', 'content': 'Your task is to summarise the text I have given you in up to seven concise bullet points, starting with a short highlight. \nYour output should use the following template: \nSummary \nHighlights \n-  Bulletpoint \n"' },
                { 'role': 'user', 'content': `${text}` }
            ],
            'max_tokens': 800,
            'temperature': 0
        };

        const response = await fetch('https://api.openai.com/v1/chat/completions', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}`
            },
            body: JSON.stringify(requestBody)
        });

        if (response.ok) {
            const data = await response.json();
            const summary = data.choices[0].message.content;
            OrionInternals.setSidebarContent(summary)
        } else {
            console.error('API request failed:', await response.text());
        }
    })();

Streaming response from OpenAI API

The following is a demonstration of the code used to power the 'Summarize' button.

The code connects to OpenAI API (change apiKey with your own) and sends a prompt that will summarizes the text on the page. It uses OrionInternals.setSidebarContent(summary) method to update Orions sidebar.

(async () => {
    const apiKey = 'your_api_key';
    const text = document.title + ' ' + Array.from(document.querySelectorAll('p')).map(p => p.innerText).join(' ');
    const requestBody = {
        'model': 'gpt-3.5-turbo',
        'messages': [
            { 'role': 'system', 'content': 'Your task is to summarise the text I have given you in up to seven concise bullet points, starting with a short highlight. \nYour output should use the following template: \nSummary \nHighlights \n-  Bulletpoint \n"' },
            { 'role': 'user', 'content': `${text}` }
        ],
        'max_tokens': 800,
        'temperature': 0,
        'stream': true
    };

    const response = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
        },
        body: JSON.stringify(requestBody)
    });

    if (response.ok) {
        const reader = response.body.getReader();
        const decoder = new TextDecoder('utf-8');
        let summary = '';

        while (true) {
            const { value, done } = await reader.read();
            if (done) {
                break;
            }
            const lines = decoder.decode(value).split('\n').filter(line => line.trim() !== '');
            for (const line of lines) {
                const message = line.replace(/^data: /, '');
                if (message === '[DONE]') {
                    break;
                }
                try {
                    const parsed = JSON.parse(message);
                    const content = parsed.choices && parsed.choices[0] && parsed.choices[0].delta && parsed.choices[0].delta.content;
                    if (content) {
                        summary += content;
                        OrionInternals.setSidebarContent(summary);
                    }
                } catch (error) {
                    console.error('Could not JSON parse stream message', message, error);
                }
            }
        }

    } else {
        console.error('API request failed:', await response.text());
    }
})();