mirror of
https://github.com/wassname/chatGPTBox.git
synced 2026-08-11 11:16:18 +08:00
feat: azure openai api (#80)
This commit is contained in:
@@ -10,7 +10,7 @@ Deep ChatGPT integrations in your browser, completely for free.
|
||||
|
||||
[![license][license-image]][license-url]
|
||||
[![release][release-image]][release-url]
|
||||
[][release-url]
|
||||
[][release-url]
|
||||
[![verfiy][verify-image]][verify-url]
|
||||
|
||||
English | [Indonesia](README_IN.md) | [简体中文](README_ZH.md)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ Integrasi Deep ChatGPT di browser Anda, sepenuhnya gratis.
|
||||
|
||||
[![license][license-image]][license-url]
|
||||
[![release][release-image]][release-url]
|
||||
[][release-url]
|
||||
[][release-url]
|
||||
[![verfiy][verify-image]][verify-url]
|
||||
|
||||
[Inggris](README.md) | Indonesia | [简体中文](README_ZH.md)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
[![license][license-image]][license-url]
|
||||
[![release][release-image]][release-url]
|
||||
[][release-url]
|
||||
[][release-url]
|
||||
[![verfiy][verify-image]][verify-url]
|
||||
|
||||
[English](README.md) | [Indonesia](README_IN.md) | 简体中文
|
||||
|
||||
Generated
+32
-7
@@ -9,6 +9,7 @@
|
||||
"@nem035/gpt-3-encoder": "^1.1.7",
|
||||
"@picocss/pico": "^1.5.7",
|
||||
"@primer/octicons-react": "^18.2.0",
|
||||
"azure-openai": "^0.9.4",
|
||||
"countries-list": "^2.6.1",
|
||||
"eventsource-parser": "^0.1.0",
|
||||
"expiry-map": "^2.0.0",
|
||||
@@ -2751,8 +2752,7 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.5",
|
||||
@@ -2763,6 +2763,23 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/azure-openai": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmmirror.com/azure-openai/-/azure-openai-0.9.4.tgz",
|
||||
"integrity": "sha512-7uii4ZInxzu2zjLg45PdvgOaw3ps18tEAw0Yux9mo8anX4PwnCMSS9xdlKNiNQyyEKPogvAcxH2PIufHXFLx6Q==",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.0",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-9.1.2.tgz",
|
||||
@@ -3081,7 +3098,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -3581,7 +3597,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -4349,6 +4364,19 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz",
|
||||
@@ -4362,7 +4390,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -6295,7 +6322,6 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -6304,7 +6330,6 @@
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"@nem035/gpt-3-encoder": "^1.1.7",
|
||||
"@picocss/pico": "^1.5.7",
|
||||
"@primer/octicons-react": "^18.2.0",
|
||||
"azure-openai": "^0.9.4",
|
||||
"countries-list": "^2.6.1",
|
||||
"eventsource-parser": "^0.1.0",
|
||||
"expiry-map": "^2.0.0",
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Configuration, OpenAIApi } from 'azure-openai'
|
||||
import { getUserConfig, maxResponseTokenLength } from '../../config/index.mjs'
|
||||
import { getChatSystemPromptBase, pushRecord, setAbortController } from './shared.mjs'
|
||||
import { getConversationPairs } from '../../utils/get-conversation-pairs'
|
||||
|
||||
/**
|
||||
* @param {Runtime.Port} port
|
||||
* @param {string} question
|
||||
* @param {Session} session
|
||||
*/
|
||||
export async function generateAnswersWithAzureOpenaiApi(port, question, session) {
|
||||
const { controller, messageListener } = setAbortController(port)
|
||||
const config = await getUserConfig()
|
||||
|
||||
const prompt = getConversationPairs(session.conversationRecords, false)
|
||||
prompt.unshift({ role: 'system', content: await getChatSystemPromptBase() })
|
||||
prompt.push({ role: 'user', content: question })
|
||||
|
||||
const openAiApi = new OpenAIApi(
|
||||
new Configuration({
|
||||
apiKey: config.azureApiKey,
|
||||
azure: {
|
||||
apiKey: config.azureApiKey,
|
||||
endpoint: config.azureEndpoint,
|
||||
deploymentName: config.azureDeploymentName,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
let answer = ''
|
||||
const response = await openAiApi
|
||||
.createChatCompletion(
|
||||
{
|
||||
messages: prompt,
|
||||
stream: true,
|
||||
max_tokens: maxResponseTokenLength,
|
||||
},
|
||||
{
|
||||
signal: controller.signal,
|
||||
responseType: 'stream',
|
||||
},
|
||||
)
|
||||
.catch((err) => {
|
||||
port.onMessage.removeListener(messageListener)
|
||||
throw err
|
||||
})
|
||||
for await (const chunk of response.data) {
|
||||
const lines = chunk
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
.filter((line) => line.trim().startsWith('data: '))
|
||||
|
||||
for (const line of lines) {
|
||||
const message = line.replace(/^data: /, '')
|
||||
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 })
|
||||
break
|
||||
}
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(message)
|
||||
} catch (error) {
|
||||
console.debug('json error', error)
|
||||
continue
|
||||
}
|
||||
answer += data.choices[0].text
|
||||
port.postMessage({ answer: answer, done: false, session: null })
|
||||
}
|
||||
}
|
||||
|
||||
port.onMessage.removeListener(messageListener)
|
||||
}
|
||||
@@ -7,16 +7,8 @@ import { pushRecord, setAbortController } from './shared.mjs'
|
||||
* @param {string} question
|
||||
* @param {Session} session
|
||||
* @param {string} accessToken
|
||||
* @param {string} modelName
|
||||
*/
|
||||
export async function generateAnswersWithBingWebApi(
|
||||
port,
|
||||
question,
|
||||
session,
|
||||
accessToken,
|
||||
// eslint-disable-next-line
|
||||
modelName,
|
||||
) {
|
||||
export async function generateAnswersWithBingWebApi(port, question, session, accessToken) {
|
||||
const { controller, messageListener } = setAbortController(port)
|
||||
|
||||
const bingAIClient = new BingAIClient({ userToken: accessToken })
|
||||
|
||||
@@ -11,7 +11,9 @@ import {
|
||||
generateAnswersWithGptCompletionApi,
|
||||
} from './apis/openai-api'
|
||||
import { generateAnswersWithCustomApi } from './apis/custom-api.mjs'
|
||||
import { generateAnswersWithAzureOpenaiApi } from './apis/azure-openai-api.mjs'
|
||||
import {
|
||||
azureOpenAiApiModelKeys,
|
||||
bingWebModelKeys,
|
||||
chatgptApiModelKeys,
|
||||
chatgptWebModelKeys,
|
||||
@@ -81,13 +83,7 @@ Browser.runtime.onConnect.addListener((port) => {
|
||||
await generateAnswersWithChatgptWebApi(port, session.question, session, accessToken)
|
||||
} else if (bingWebModelKeys.includes(session.modelName)) {
|
||||
const accessToken = await getBingAccessToken()
|
||||
await generateAnswersWithBingWebApi(
|
||||
port,
|
||||
session.question,
|
||||
session,
|
||||
accessToken,
|
||||
session.modelName,
|
||||
)
|
||||
await generateAnswersWithBingWebApi(port, session.question, session, accessToken)
|
||||
} else if (gptApiModelKeys.includes(session.modelName)) {
|
||||
await generateAnswersWithGptCompletionApi(
|
||||
port,
|
||||
@@ -112,6 +108,8 @@ Browser.runtime.onConnect.addListener((port) => {
|
||||
'',
|
||||
config.customModelName,
|
||||
)
|
||||
} else if (azureOpenAiApiModelKeys.includes(session.modelName)) {
|
||||
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
||||
+17
-9
@@ -19,6 +19,7 @@ export const Models = {
|
||||
chatgptApi4_32k: { value: 'gpt-4-32k', desc: 'ChatGPT (GPT-4-32k)' },
|
||||
gptApiDavinci: { value: 'text-davinci-003', desc: 'GPT-3.5' },
|
||||
customModel: { value: '', desc: 'Custom Model' },
|
||||
azureOpenAi: { value: '', desc: 'ChatGPT (Azure)' },
|
||||
}
|
||||
|
||||
export const chatgptWebModelKeys = ['chatgptFree35', 'chatgptPlus4']
|
||||
@@ -26,6 +27,7 @@ export const bingWebModelKeys = ['bingFree4']
|
||||
export const gptApiModelKeys = ['gptApiDavinci']
|
||||
export const chatgptApiModelKeys = ['chatgptApi35', 'chatgptApi4_8k', 'chatgptApi4_32k']
|
||||
export const customApiModelKeys = ['customModel']
|
||||
export const azureOpenAiApiModelKeys = ['azureOpenAi']
|
||||
|
||||
export const TriggerMode = {
|
||||
always: 'Always',
|
||||
@@ -60,13 +62,21 @@ export const defaultConfig = {
|
||||
themeMode: 'auto',
|
||||
/** @type {keyof Models}*/
|
||||
modelName: 'chatgptFree35',
|
||||
apiKey: '',
|
||||
/** @type {keyof ModelMode}*/
|
||||
modelMode: 'balanced',
|
||||
|
||||
preferredLanguage: getNavigatorLanguage(),
|
||||
insertAtTop: isMobile(),
|
||||
lockWhenAnswer: false,
|
||||
autoRegenAfterSwitchModel: false,
|
||||
|
||||
apiKey: '', // openai ApiKey
|
||||
|
||||
azureApiKey: '',
|
||||
azureEndpoint: '',
|
||||
azureDeploymentName: '',
|
||||
|
||||
/** @type {keyof ModelMode}*/
|
||||
modelMode: 'balanced',
|
||||
|
||||
customModelApiUrl: 'http://localhost:8000/chat/completions',
|
||||
customModelName: 'llama-7b-int4',
|
||||
|
||||
@@ -154,6 +164,10 @@ export function isUsingCustomModel(configOrSession) {
|
||||
return customApiModelKeys.includes(configOrSession.modelName)
|
||||
}
|
||||
|
||||
export function isUsingAzureOpenAi(configOrSession) {
|
||||
return azureOpenAiApiModelKeys.includes(configOrSession.modelName)
|
||||
}
|
||||
|
||||
export async function getPreferredLanguageKey() {
|
||||
const config = await getUserConfig()
|
||||
if (config.preferredLanguage === 'auto') return config.userLanguage
|
||||
@@ -166,12 +180,6 @@ export async function getPreferredLanguageKey() {
|
||||
*/
|
||||
export async function getUserConfig() {
|
||||
const options = await Browser.storage.local.get(Object.keys(defaultConfig))
|
||||
|
||||
// version compatibility
|
||||
if (options.modelName === 'chatgptFree') options.modelName = 'chatgptFree35'
|
||||
else if (options.modelName === 'chatgptApi') options.modelName = 'chatgptApi35'
|
||||
else if (options.modelName === 'gptDavinci') options.modelName = 'gptApiDavinci'
|
||||
|
||||
return defaults(options, defaultConfig)
|
||||
}
|
||||
|
||||
|
||||
+39
-1
@@ -5,6 +5,7 @@ import {
|
||||
getPreferredLanguageKey,
|
||||
getUserConfig,
|
||||
isUsingApiKey,
|
||||
isUsingAzureOpenAi,
|
||||
isUsingCustomModel,
|
||||
isUsingMultiModeModel,
|
||||
ModelMode,
|
||||
@@ -85,7 +86,10 @@ function GeneralPart({ config, updateConfig }) {
|
||||
<span style="display: flex; gap: 15px;">
|
||||
<select
|
||||
style={
|
||||
isUsingApiKey(config) || isUsingMultiModeModel(config) || isUsingCustomModel(config)
|
||||
isUsingApiKey(config) ||
|
||||
isUsingMultiModeModel(config) ||
|
||||
isUsingCustomModel(config) ||
|
||||
isUsingAzureOpenAi(config)
|
||||
? 'width: 50%;'
|
||||
: undefined
|
||||
}
|
||||
@@ -165,6 +169,18 @@ function GeneralPart({ config, updateConfig }) {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isUsingAzureOpenAi(config) && (
|
||||
<input
|
||||
type="password"
|
||||
style="width: 50%;"
|
||||
value={config.azureApiKey}
|
||||
placeholder={t('Azure API Key')}
|
||||
onChange={(e) => {
|
||||
const apiKey = e.target.value
|
||||
updateConfig({ azureApiKey: apiKey })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
{isUsingCustomModel(config) && (
|
||||
<input
|
||||
@@ -177,6 +193,28 @@ function GeneralPart({ config, updateConfig }) {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isUsingAzureOpenAi(config) && (
|
||||
<input
|
||||
type="password"
|
||||
value={config.azureEndpoint}
|
||||
placeholder={t('Azure Endpoint')}
|
||||
onChange={(e) => {
|
||||
const endpoint = e.target.value
|
||||
updateConfig({ azureEndpoint: endpoint })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isUsingAzureOpenAi(config) && (
|
||||
<input
|
||||
type="text"
|
||||
value={config.azureDeploymentName}
|
||||
placeholder={t('Azure Deployment Name')}
|
||||
onChange={(e) => {
|
||||
const deploymentName = e.target.value
|
||||
updateConfig({ azureDeploymentName: deploymentName })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</label>
|
||||
<label>
|
||||
<legend>{t('Preferred Language')}</legend>
|
||||
|
||||
Reference in New Issue
Block a user