Skip to content

Commit 8f274c1

Browse files
committed
feat: azure openai api (#80)
1 parent abccc6c commit 8f274c1

File tree

10 files changed

+173
-36
lines changed

10 files changed

+173
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Deep ChatGPT integrations in your browser, completely for free.
1010

1111
[![license][license-image]][license-url]
1212
[![release][release-image]][release-url]
13-
[![size](https://img.shields.io/badge/minified%20size-350%20kB-blue)][release-url]
13+
[![size](https://img.shields.io/badge/minified%20size-360%20kB-blue)][release-url]
1414
[![verfiy][verify-image]][verify-url]
1515

1616
English | [Indonesia](README_IN.md) | [简体中文](README_ZH.md)

README_IN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Integrasi Deep ChatGPT di browser Anda, sepenuhnya gratis.
1010

1111
[![license][license-image]][license-url]
1212
[![release][release-image]][release-url]
13-
[![size](https://img.shields.io/badge/minified%20size-350%20kB-blue)][release-url]
13+
[![size](https://img.shields.io/badge/minified%20size-360%20kB-blue)][release-url]
1414
[![verfiy][verify-image]][verify-url]
1515

1616
[Inggris](README.md) | Indonesia | [简体中文](README_ZH.md)

README_ZH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
[![license][license-image]][license-url]
1212
[![release][release-image]][release-url]
13-
[![size](https://img.shields.io/badge/minified%20size-350%20kB-blue)][release-url]
13+
[![size](https://img.shields.io/badge/minified%20size-360%20kB-blue)][release-url]
1414
[![verfiy][verify-image]][verify-url]
1515

1616
[English](README.md) | [Indonesia](README_IN.md) | 简体中文

package-lock.json

Lines changed: 32 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@nem035/gpt-3-encoder": "^1.1.7",
2323
"@picocss/pico": "^1.5.7",
2424
"@primer/octicons-react": "^18.2.0",
25+
"azure-openai": "^0.9.4",
2526
"countries-list": "^2.6.1",
2627
"eventsource-parser": "^0.1.0",
2728
"expiry-map": "^2.0.0",
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Configuration, OpenAIApi } from 'azure-openai'
2+
import { getUserConfig, maxResponseTokenLength } from '../../config/index.mjs'
3+
import { getChatSystemPromptBase, pushRecord, setAbortController } from './shared.mjs'
4+
import { getConversationPairs } from '../../utils/get-conversation-pairs'
5+
6+
/**
7+
* @param {Runtime.Port} port
8+
* @param {string} question
9+
* @param {Session} session
10+
*/
11+
export async function generateAnswersWithAzureOpenaiApi(port, question, session) {
12+
const { controller, messageListener } = setAbortController(port)
13+
const config = await getUserConfig()
14+
15+
const prompt = getConversationPairs(session.conversationRecords, false)
16+
prompt.unshift({ role: 'system', content: await getChatSystemPromptBase() })
17+
prompt.push({ role: 'user', content: question })
18+
19+
const openAiApi = new OpenAIApi(
20+
new Configuration({
21+
apiKey: config.azureApiKey,
22+
azure: {
23+
apiKey: config.azureApiKey,
24+
endpoint: config.azureEndpoint,
25+
deploymentName: config.azureDeploymentName,
26+
},
27+
}),
28+
)
29+
30+
let answer = ''
31+
const response = await openAiApi
32+
.createChatCompletion(
33+
{
34+
messages: prompt,
35+
stream: true,
36+
max_tokens: maxResponseTokenLength,
37+
},
38+
{
39+
signal: controller.signal,
40+
responseType: 'stream',
41+
},
42+
)
43+
.catch((err) => {
44+
port.onMessage.removeListener(messageListener)
45+
throw err
46+
})
47+
for await (const chunk of response.data) {
48+
const lines = chunk
49+
.toString('utf8')
50+
.split('\n')
51+
.filter((line) => line.trim().startsWith('data: '))
52+
53+
for (const line of lines) {
54+
const message = line.replace(/^data: /, '')
55+
console.debug('sse message', message)
56+
if (message === '[DONE]') {
57+
pushRecord(session, question, answer)
58+
console.debug('conversation history', { content: session.conversationRecords })
59+
port.postMessage({ answer: null, done: true, session: session })
60+
break
61+
}
62+
let data
63+
try {
64+
data = JSON.parse(message)
65+
} catch (error) {
66+
console.debug('json error', error)
67+
continue
68+
}
69+
answer += data.choices[0].text
70+
port.postMessage({ answer: answer, done: false, session: null })
71+
}
72+
}
73+
74+
port.onMessage.removeListener(messageListener)
75+
}

src/background/apis/bing-web.mjs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,8 @@ import { pushRecord, setAbortController } from './shared.mjs'
77
* @param {string} question
88
* @param {Session} session
99
* @param {string} accessToken
10-
* @param {string} modelName
1110
*/
12-
export async function generateAnswersWithBingWebApi(
13-
port,
14-
question,
15-
session,
16-
accessToken,
17-
// eslint-disable-next-line
18-
modelName,
19-
) {
11+
export async function generateAnswersWithBingWebApi(port, question, session, accessToken) {
2012
const { controller, messageListener } = setAbortController(port)
2113

2214
const bingAIClient = new BingAIClient({ userToken: accessToken })

src/background/index.mjs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import {
1111
generateAnswersWithGptCompletionApi,
1212
} from './apis/openai-api'
1313
import { generateAnswersWithCustomApi } from './apis/custom-api.mjs'
14+
import { generateAnswersWithAzureOpenaiApi } from './apis/azure-openai-api.mjs'
1415
import {
16+
azureOpenAiApiModelKeys,
1517
bingWebModelKeys,
1618
chatgptApiModelKeys,
1719
chatgptWebModelKeys,
@@ -81,13 +83,7 @@ Browser.runtime.onConnect.addListener((port) => {
8183
await generateAnswersWithChatgptWebApi(port, session.question, session, accessToken)
8284
} else if (bingWebModelKeys.includes(session.modelName)) {
8385
const accessToken = await getBingAccessToken()
84-
await generateAnswersWithBingWebApi(
85-
port,
86-
session.question,
87-
session,
88-
accessToken,
89-
session.modelName,
90-
)
86+
await generateAnswersWithBingWebApi(port, session.question, session, accessToken)
9187
} else if (gptApiModelKeys.includes(session.modelName)) {
9288
await generateAnswersWithGptCompletionApi(
9389
port,
@@ -112,6 +108,8 @@ Browser.runtime.onConnect.addListener((port) => {
112108
'',
113109
config.customModelName,
114110
)
111+
} else if (azureOpenAiApiModelKeys.includes(session.modelName)) {
112+
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
115113
}
116114
} catch (err) {
117115
console.error(err)

src/config/index.mjs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ export const Models = {
1919
chatgptApi4_32k: { value: 'gpt-4-32k', desc: 'ChatGPT (GPT-4-32k)' },
2020
gptApiDavinci: { value: 'text-davinci-003', desc: 'GPT-3.5' },
2121
customModel: { value: '', desc: 'Custom Model' },
22+
azureOpenAi: { value: '', desc: 'ChatGPT (Azure)' },
2223
}
2324

2425
export const chatgptWebModelKeys = ['chatgptFree35', 'chatgptPlus4']
2526
export const bingWebModelKeys = ['bingFree4']
2627
export const gptApiModelKeys = ['gptApiDavinci']
2728
export const chatgptApiModelKeys = ['chatgptApi35', 'chatgptApi4_8k', 'chatgptApi4_32k']
2829
export const customApiModelKeys = ['customModel']
30+
export const azureOpenAiApiModelKeys = ['azureOpenAi']
2931

3032
export const TriggerMode = {
3133
always: 'Always',
@@ -60,13 +62,21 @@ export const defaultConfig = {
6062
themeMode: 'auto',
6163
/** @type {keyof Models}*/
6264
modelName: 'chatgptFree35',
63-
apiKey: '',
64-
/** @type {keyof ModelMode}*/
65-
modelMode: 'balanced',
65+
6666
preferredLanguage: getNavigatorLanguage(),
6767
insertAtTop: isMobile(),
6868
lockWhenAnswer: false,
6969
autoRegenAfterSwitchModel: false,
70+
71+
apiKey: '', // openai ApiKey
72+
73+
azureApiKey: '',
74+
azureEndpoint: '',
75+
azureDeploymentName: '',
76+
77+
/** @type {keyof ModelMode}*/
78+
modelMode: 'balanced',
79+
7080
customModelApiUrl: 'http://localhost:8000/chat/completions',
7181
customModelName: 'llama-7b-int4',
7282

@@ -154,6 +164,10 @@ export function isUsingCustomModel(configOrSession) {
154164
return customApiModelKeys.includes(configOrSession.modelName)
155165
}
156166

167+
export function isUsingAzureOpenAi(configOrSession) {
168+
return azureOpenAiApiModelKeys.includes(configOrSession.modelName)
169+
}
170+
157171
export async function getPreferredLanguageKey() {
158172
const config = await getUserConfig()
159173
if (config.preferredLanguage === 'auto') return config.userLanguage
@@ -166,12 +180,6 @@ export async function getPreferredLanguageKey() {
166180
*/
167181
export async function getUserConfig() {
168182
const options = await Browser.storage.local.get(Object.keys(defaultConfig))
169-
170-
// version compatibility
171-
if (options.modelName === 'chatgptFree') options.modelName = 'chatgptFree35'
172-
else if (options.modelName === 'chatgptApi') options.modelName = 'chatgptApi35'
173-
else if (options.modelName === 'gptDavinci') options.modelName = 'gptApiDavinci'
174-
175183
return defaults(options, defaultConfig)
176184
}
177185

src/popup/Popup.jsx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getPreferredLanguageKey,
66
getUserConfig,
77
isUsingApiKey,
8+
isUsingAzureOpenAi,
89
isUsingCustomModel,
910
isUsingMultiModeModel,
1011
ModelMode,
@@ -85,7 +86,10 @@ function GeneralPart({ config, updateConfig }) {
8586
<span style="display: flex; gap: 15px;">
8687
<select
8788
style={
88-
isUsingApiKey(config) || isUsingMultiModeModel(config) || isUsingCustomModel(config)
89+
isUsingApiKey(config) ||
90+
isUsingMultiModeModel(config) ||
91+
isUsingCustomModel(config) ||
92+
isUsingAzureOpenAi(config)
8993
? 'width: 50%;'
9094
: undefined
9195
}
@@ -165,6 +169,18 @@ function GeneralPart({ config, updateConfig }) {
165169
}}
166170
/>
167171
)}
172+
{isUsingAzureOpenAi(config) && (
173+
<input
174+
type="password"
175+
style="width: 50%;"
176+
value={config.azureApiKey}
177+
placeholder={t('Azure API Key')}
178+
onChange={(e) => {
179+
const apiKey = e.target.value
180+
updateConfig({ azureApiKey: apiKey })
181+
}}
182+
/>
183+
)}
168184
</span>
169185
{isUsingCustomModel(config) && (
170186
<input
@@ -177,6 +193,28 @@ function GeneralPart({ config, updateConfig }) {
177193
}}
178194
/>
179195
)}
196+
{isUsingAzureOpenAi(config) && (
197+
<input
198+
type="password"
199+
value={config.azureEndpoint}
200+
placeholder={t('Azure Endpoint')}
201+
onChange={(e) => {
202+
const endpoint = e.target.value
203+
updateConfig({ azureEndpoint: endpoint })
204+
}}
205+
/>
206+
)}
207+
{isUsingAzureOpenAi(config) && (
208+
<input
209+
type="text"
210+
value={config.azureDeploymentName}
211+
placeholder={t('Azure Deployment Name')}
212+
onChange={(e) => {
213+
const deploymentName = e.target.value
214+
updateConfig({ azureDeploymentName: deploymentName })
215+
}}
216+
/>
217+
)}
180218
</label>
181219
<label>
182220
<legend>{t('Preferred Language')}</legend>

0 commit comments

Comments
 (0)