Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PromptCritic] Streaming #166

Merged
merged 8 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@types/jest": "^29.5.2",
"@types/node": "20.2.5",
"@types/react": "^18.2.8",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-dom": "^18.2.4",
"@types/react-test-renderer": "^18.0.0",
"@types/terser-webpack-plugin": "^5.0.4",
Expand Down
9 changes: 7 additions & 2 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface ProviderInterface {
fullName: string;
shortName: string;
webviewId: string;
getWebview(): HTMLElement;
getWebview(): HTMLElement | null;
url: string;
paneId(): string;
setupCustomPasteBehavior(): void;
Expand All @@ -16,7 +16,12 @@ export interface ProviderInterface {
getUserAgent(): string;
isEnabled(): boolean;
setEnabled(enabled: boolean): void;
clearCookies(): void;
clearCookies?(): void;

codeForInputElement?: string;
codeForSetInputElementValue?(prompt: string): void;
codeForClickingSubmit?: string;
codeForExtractingResponse?: string;
}

export interface Settings {
Expand Down
91 changes: 91 additions & 0 deletions src/main/apify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { ProviderInterface } from 'lib/types';
import { BrowserWindow } from 'electron';

export async function streamChatResponse(opts: {
provider: ProviderInterface;
prompt: string;
sendFn: (...args: any[]) => void | undefined;
}) {
const win = new BrowserWindow({
// show: true,
show: false,
// titleBarStyle: 'hidden',
// width: 800,
// height: 600,
// webPreferences: {
// webviewTag: true,
// nodeIntegration: true,
// },
});
win.loadURL(opts.provider.url);

return new Promise((resolve, reject) => {
win.webContents.on('dom-ready', async () => {
try {
// check if logged in (and inputElement exists)
await win.webContents.executeJavaScript(
`{${opts.provider.codeForInputElement}}`,
);
} catch (err) {
console.error(
'input element doesnt exist: ',
opts.provider.codeForInputElement,
);
return reject(err);
}
await timeout(500);
const script = `{
${opts.provider.codeForInputElement}
${opts.provider.codeForSetInputElementValue!(opts.prompt)}
${opts.provider.codeForClickingSubmit}
}`;
await win.webContents.executeJavaScript(script);
console.log('script', script);

// Define two variables to store the previous responses
let lastResponseHTML = null;
let secondLastResponseHTML = null;

console.log('looping');
// Loop until our condition is met
await timeout(300);
while (true) {
await timeout(300);
// await win.webContents.executeJavaScript(
// `console.log('hiii', [...document.querySelectorAll('.default.font-sans.text-base.text-textMain .prose')]);`,
// );
var responseHTML = await win.webContents.executeJavaScript(
`${opts.provider.codeForExtractingResponse}.innerHTML`,
);
var responseText = await win.webContents.executeJavaScript(
`${opts.provider.codeForExtractingResponse}.innerText`,
);

console.log({ responseHTML, secondLastResponseHTML });
// If responseHTML hasn't changed for 2 invocations, break
if (
responseHTML === lastResponseHTML &&
responseHTML === secondLastResponseHTML
) {
console.log('prompting');
break;
}

// Shift our stored responses for the next loop iteration
secondLastResponseHTML = lastResponseHTML;
lastResponseHTML = responseHTML;

console.log('sendFn', responseText);
opts.sendFn(responseHTML, responseText); // stream incomplete responses back
}
console.log('closing');
win.close();
return resolve({ responseHTML, responseText });
});
});
}
// thanks claude

function timeout(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
74 changes: 15 additions & 59 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import Store from 'electron-store';
import MenuBuilder from './menu';
import { streamChatResponse } from './apify';
import { resolveHtmlPath } from './util';
import { isValidShortcut } from '../lib/utils';
import PerplexityLlama from '../providers/perplexity-llama';

let store = new Store();

Expand Down Expand Up @@ -66,61 +68,15 @@ ipcMain.on('get-always-on-top', async (event, property, val) => {
event.returnValue = bool;
});

// thanks claude

function timeout(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getLlamaResponse(prompt: string) {
const win = new BrowserWindow({
// show: true,
show: false,
// titleBarStyle: 'hidden',
// width: 800,
// height: 600,
// webPreferences: {
// webviewTag: true,
// nodeIntegration: true,
// },
ipcMain.on('prompt-hidden-chat', async (event, channel: string, prompt) => {
const sendFn = (...args: any[]) =>
mainWindow?.webContents.send(channel, ...args);
const done = await streamChatResponse({
provider: PerplexityLlama,
prompt,
sendFn,
});
win.loadURL('https://labs.perplexity.ai');
return new Promise((resolve, reject) => {
win.webContents.on('dom-ready', async () => {
await win.webContents.executeJavaScript(`{
var selectElement = document.querySelector('#lamma-select');
selectElement.value = 'llama-2-70b-chat';

var inputElement = document.querySelector('textarea[placeholder*="Ask"]'); // can be "Ask anything" or "Ask follow-up"
inputElement.focus();
var nativeTextAreaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
nativeTextAreaValueSetter.call(inputElement, \`${prompt}\`);

var event = new Event('input', { bubbles: true});
inputElement.dispatchEvent(event);
var buttons = Array.from(document.querySelectorAll('button.bg-super'));
var buttonsWithSvgPath = buttons.filter(button => button.querySelector('svg path'));
var button = buttonsWithSvgPath[buttonsWithSvgPath.length - 1];
button.click();
}`);
await timeout(5000);
// const temp = await win.webContents.executeJavaScript(`
// [...document.querySelectorAll('.default.font-sans.text-base.text-textMain .prose')].map(x => x.innerHTML)
// `);
// console.log('temp', temp);
const responseHTML = await win.webContents.executeJavaScript(`
[...document.querySelectorAll('.default.font-sans.text-base.text-textMain .prose')].slice(-1)[0].innerHTML
`);
const responseText = await win.webContents.executeJavaScript(`
[...document.querySelectorAll('.default.font-sans.text-base.text-textMain .prose')].slice(-1)[0].innerText
`);
resolve({ responseHTML, responseText });
win.close();
});
});
}
ipcMain.on('prompt-llama2', async (event, val) => {
const response = await getLlamaResponse(val);
event.returnValue = response;
event.returnValue = done; // {responseHTML, responseText}
});

/*
Expand Down Expand Up @@ -219,11 +175,11 @@ const createWindow = async () => {
const menuBuilder = new MenuBuilder(mainWindow);
menuBuilder.buildMenu();

// // Open urls in the user's browser
// mainWindow.webContents.setWindowOpenHandler((edata) => {
// shell.openExternal(edata.url);
// return { action: 'allow' };
// });
// Open urls in the user's browser
mainWindow.webContents.setWindowOpenHandler((edata) => {
shell.openExternal(edata.url);
return { action: 'allow' };
});

// Remove this if your app does not use auto updates
// eslint-disable-next-line
Expand Down
7 changes: 3 additions & 4 deletions src/main/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint no-unused-vars: off */
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';

export type Channels = 'ipc-example';
export type Channels = 'ipc-example' | 'perplexity-llama2';

const electronHandler = {
ipcRenderer: {
Expand Down Expand Up @@ -44,9 +44,8 @@ const electronHandler = {
setAlwaysOnTop(val: any) {
ipcRenderer.send('set-always-on-top', val);
},
promptLlama2(prompt: string) {
const response = ipcRenderer.sendSync('prompt-llama2', prompt);
return response;
promptHiddenChat(prompt: string) {
ipcRenderer.send('prompt-hidden-chat', 'perplexity-llama2', prompt);
},
},
};
Expand Down
12 changes: 5 additions & 7 deletions src/providers/bing.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,21 @@ class Bing extends Provider {

// SERP Shadow DOM
var serpDOM = document.querySelector('.cib-serp-main');
if (!serpDOM) {
console.error('serpDOM for ${fullName} doesnt exist, have you logged in or are you on the right page?')
}

// Action Bar Shadow DOM
var inputDOM = serpDOM.shadowRoot.querySelector('#cib-action-bar-main');
if (!inputDOM) {
console.error('inputDOM for ${fullName} doesnt exist, have you logged in or are you on the right page?')
}

// Text Input Shadow DOM
var textInputDOM = inputDOM.shadowRoot.querySelector('cib-text-input');

// This inner cib-text-input Shadow DOM is not always present
var inputElement = textInputDOM ? textInputDOM.shadowRoot.querySelector('#searchbox') : inputDOM.shadowRoot.querySelector('#searchbox');

simulateUserInput(inputElement, \`${input}\`);
if (!inputElement) {
console.error('inputElement for \`${fullName}\` doesnt exist, have you logged in or are you on the right page?')
} else {
simulateUserInput(inputElement, \`${input}\`);
}
}
`);
}
Expand Down
2 changes: 1 addition & 1 deletion src/providers/claude2.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class Claude2 extends Provider {
}

static isEnabled() {
return window.electron.electronStore.get(`${this.webviewId}Enabled`, false);
return window.electron.electronStore.get(`${this.webviewId}Enabled`, true);
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/providers/perplexity-llama.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ class PerplexityLlama extends Provider {
}
}

static codeForInputElement = `var inputElement = document.querySelector('textarea[placeholder*="Ask"]');`;
static codeForSetInputElementValue(prompt) {
return `
var nativeTextAreaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
nativeTextAreaValueSetter.call(inputElement, \`${prompt}\`);
var event = new Event('input', { bubbles: true});
inputElement.dispatchEvent(event);
`;
}
static codeForClickingSubmit = `
var buttons = Array.from(document.querySelectorAll('button.bg-super'));
var buttonsWithSvgPath = buttons.filter(button => button.querySelector('svg path'));

var button = buttonsWithSvgPath[buttonsWithSvgPath.length - 1];

button.click();
`;
static codeForExtractingResponse = `[...document.querySelectorAll('.default.font-sans.text-base.text-textMain .prose')].slice(-1)[0]`; // dont append semicolon, we will append innerhtml etc

static handleSubmit() {
try {
this.getWebview().executeJavaScript(`{
Expand Down
2 changes: 1 addition & 1 deletion src/providers/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class Provider {
}

static getUserAgent() {
return false;
return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.37';
}

static isEnabled() {
Expand Down
10 changes: 6 additions & 4 deletions src/providers/smol.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ class SmolTalk extends Provider {
this.getWebview().executeJavaScript(`{

var btn = document.querySelector('#smol-submitbtn');
if (btn) {
btn.focus();
btn.setAttribute("aria-disabled", "false"); // doesnt work alone
btn.disabled = false;
btn.click()
}

btn.focus();
btn.setAttribute("aria-disabled", "false"); // doesnt work alone
btn.disabled = false;
btn.click()
}`);
}

Expand Down
Loading