From 4f78d225afcc63821d37ce90b756d7c783d013f9 Mon Sep 17 00:00:00 2001 From: josc146 Date: Wed, 12 Apr 2023 21:37:07 +0800 Subject: [PATCH] feat: support waylaidwanderer self-hosted api (#182) --- src/background/apis/bing-web.mjs | 18 ++--- src/background/apis/waylaidwanderer-api.mjs | 76 +++++++++++++++++++++ src/background/index.mjs | 4 ++ src/config/index.mjs | 7 ++ src/popup/Popup.jsx | 12 ++++ src/utils/init-session.mjs | 22 +++--- 6 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 src/background/apis/waylaidwanderer-api.mjs diff --git a/src/background/apis/bing-web.mjs b/src/background/apis/bing-web.mjs index 3236c0a..5dddb14 100644 --- a/src/background/apis/bing-web.mjs +++ b/src/background/apis/bing-web.mjs @@ -24,12 +24,12 @@ export async function generateAnswersWithBingWebApi(port, question, session, acc answer = answer.replaceAll(/\[\^\d+\^\]/g, '') port.postMessage({ answer: answer, done: false, session: null }) }, - ...(session.bingWeb.conversationId + ...(session.bingWeb_conversationId ? { - conversationId: session.bingWeb.conversationId, - conversationSignature: session.bingWeb.conversationSignature, - clientId: session.bingWeb.clientId, - invocationId: session.bingWeb.invocationId, + conversationId: session.bingWeb_conversationId, + conversationSignature: session.bingWeb_conversationSignature, + clientId: session.bingWeb_clientId, + invocationId: session.bingWeb_invocationId, } : {}), }) @@ -38,10 +38,10 @@ export async function generateAnswersWithBingWebApi(port, question, session, acc throw err }) - session.bingWeb.conversationSignature = response.conversationSignature - session.bingWeb.conversationId = response.conversationId - session.bingWeb.clientId = response.clientId - session.bingWeb.invocationId = response.invocationId + session.bingWeb_conversationSignature = response.conversationSignature + session.bingWeb_conversationId = response.conversationId + session.bingWeb_clientId = response.clientId + session.bingWeb_invocationId = response.invocationId pushRecord(session, question, answer) console.debug('conversation history', { content: session.conversationRecords }) diff --git a/src/background/apis/waylaidwanderer-api.mjs b/src/background/apis/waylaidwanderer-api.mjs new file mode 100644 index 0000000..012eab9 --- /dev/null +++ b/src/background/apis/waylaidwanderer-api.mjs @@ -0,0 +1,76 @@ +import { pushRecord, setAbortController } from './shared.mjs' +import { getUserConfig } from '../../config/index.mjs' +import { fetchSSE } from '../../utils/fetch-sse' +import { isEmpty } from 'lodash-es' + +/** + * @param {Runtime.Port} port + * @param {string} question + * @param {Session} session + */ +export async function generateAnswersWithWaylaidwandererApi(port, question, session) { + const { controller, messageListener } = setAbortController(port) + + const config = await getUserConfig() + + let answer = '' + await fetchSSE(config.githubThirdPartyUrl, { + method: 'POST', + signal: controller.signal, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + message: question, + stream: true, + ...(session.bingWeb_conversationId && { + conversationId: session.bingWeb_conversationId, + conversationSignature: session.bingWeb_conversationSignature, + clientId: session.bingWeb_clientId, + invocationId: session.bingWeb_invocationId, + }), + ...(session.conversationId && { + conversationId: session.conversationId, + parentMessageId: session.parentMessageId, + }), + }), + onMessage(message) { + console.debug('sse message', message) + if (message === '[DONE]') { + pushRecord(session, question, answer) + console.debug('conversation history', { content: session.conversationRecords }) + port.postMessage({ answer: null, done: true, session: session }) + return + } + let data + try { + data = JSON.parse(message) + } catch (error) { + console.debug('json error', error) + return + } + if (data.conversationId) session.conversationId = data.conversationId + if (data.parentMessageId) session.parentMessageId = data.parentMessageId + if (data.conversationSignature) + session.bingWeb_conversationSignature = data.conversationSignature + if (data.conversationId) session.bingWeb_conversationId = data.conversationId + if (data.clientId) session.bingWeb_clientId = data.clientId + if (data.invocationId) session.bingWeb_invocationId = data.invocationId + + if (typeof data === 'string') { + answer += data + port.postMessage({ answer: answer, done: false, session: null }) + } + }, + async onStart() {}, + async onEnd() { + port.onMessage.removeListener(messageListener) + }, + async onError(resp) { + port.onMessage.removeListener(messageListener) + if (resp instanceof Error) throw resp + const error = await resp.json().catch(() => ({})) + throw new Error(!isEmpty(error) ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`) + }, + }) +} diff --git a/src/background/index.mjs b/src/background/index.mjs index 4b76526..968d7f7 100644 --- a/src/background/index.mjs +++ b/src/background/index.mjs @@ -12,6 +12,7 @@ import { } from './apis/openai-api' import { generateAnswersWithCustomApi } from './apis/custom-api.mjs' import { generateAnswersWithAzureOpenaiApi } from './apis/azure-openai-api.mjs' +import { generateAnswersWithWaylaidwandererApi } from './apis/waylaidwanderer-api.mjs' import { azureOpenAiApiModelKeys, bingWebModelKeys, @@ -21,6 +22,7 @@ import { defaultConfig, getPreferredLanguageKey, getUserConfig, + githubThirdPartyApiModelKeys, gptApiModelKeys, Models, } from '../config/index.mjs' @@ -110,6 +112,8 @@ Browser.runtime.onConnect.addListener((port) => { ) } else if (azureOpenAiApiModelKeys.includes(session.modelName)) { await generateAnswersWithAzureOpenaiApi(port, session.question, session) + } else if (githubThirdPartyApiModelKeys.includes(session.modelName)) { + await generateAnswersWithWaylaidwandererApi(port, session.question, session) } } catch (err) { console.error(err) diff --git a/src/config/index.mjs b/src/config/index.mjs index 8b358e3..020046c 100644 --- a/src/config/index.mjs +++ b/src/config/index.mjs @@ -20,6 +20,7 @@ export const Models = { gptApiDavinci: { value: 'text-davinci-003', desc: 'GPT-3.5' }, customModel: { value: '', desc: 'Custom Model' }, azureOpenAi: { value: '', desc: 'ChatGPT (Azure)' }, + waylaidwandererApi: { value: '', desc: 'Waylaidwanderer API (Github)' }, } export const chatgptWebModelKeys = ['chatgptFree35', 'chatgptPlus4'] @@ -28,6 +29,7 @@ export const gptApiModelKeys = ['gptApiDavinci'] export const chatgptApiModelKeys = ['chatgptApi35', 'chatgptApi4_8k', 'chatgptApi4_32k'] export const customApiModelKeys = ['customModel'] export const azureOpenAiApiModelKeys = ['azureOpenAi'] +export const githubThirdPartyApiModelKeys = ['waylaidwandererApi'] export const TriggerMode = { always: 'Always', @@ -77,6 +79,7 @@ export const defaultConfig = { customModelApiUrl: 'http://localhost:8000/chat/completions', customModelName: 'llama-7b-int4', + githubThirdPartyUrl: 'http://127.0.0.1:3000/conversation', // advanced @@ -167,6 +170,10 @@ export function isUsingAzureOpenAi(configOrSession) { return azureOpenAiApiModelKeys.includes(configOrSession.modelName) } +export function isUsingGithubThirdPartyApi(configOrSession) { + return githubThirdPartyApiModelKeys.includes(configOrSession.modelName) +} + export async function getPreferredLanguageKey() { const config = await getUserConfig() if (config.preferredLanguage === 'auto') return config.userLanguage diff --git a/src/popup/Popup.jsx b/src/popup/Popup.jsx index 1198515..170fbb5 100644 --- a/src/popup/Popup.jsx +++ b/src/popup/Popup.jsx @@ -7,6 +7,7 @@ import { isUsingApiKey, isUsingAzureOpenAi, isUsingCustomModel, + isUsingGithubThirdPartyApi, isUsingMultiModeModel, ModelMode, Models, @@ -215,6 +216,17 @@ function GeneralPart({ config, updateConfig }) { }} /> )} + {isUsingGithubThirdPartyApi(config) && ( + { + const url = e.target.value + updateConfig({ githubThirdPartyUrl: url }) + }} + /> + )}