-
Notifications
You must be signed in to change notification settings - Fork 854
Expand file tree
/
Copy pathazure-openai-api.mjs
More file actions
89 lines (85 loc) · 2.98 KB
/
azure-openai-api.mjs
File metadata and controls
89 lines (85 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { getUserConfig } from '../../config/index.mjs'
import { pushRecord, setAbortController } from './shared.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { isEmpty } from 'lodash-es'
import { getModelValue } from '../../utils/model-name-convert.mjs'
/**
* @param {Runtime.Port} port
* @param {string} question
* @param {Session} session
*/
export async function generateAnswersWithAzureOpenaiApi(port, question, session) {
const { controller, messageListener, disconnectListener } = setAbortController(port)
const config = await getUserConfig()
let model = getModelValue(session)
if (!model) model = config.azureDeploymentName
const prompt = getConversationPairs(
session.conversationRecords.slice(-config.maxConversationContextLength),
false,
)
prompt.push({ role: 'user', content: question })
let answer = ''
await fetchSSE(
`${config.azureEndpoint.replace(
/\/$/,
'',
)}/openai/deployments/${model}/chat/completions?api-version=2024-02-01`,
{
method: 'POST',
signal: controller.signal,
headers: {
'Content-Type': 'application/json',
'api-key': config.azureApiKey,
},
body: JSON.stringify({
messages: prompt,
stream: true,
max_tokens: config.maxResponseTokenLength,
temperature: config.temperature,
presence_penalty: config.presence_penalty,
frequency_penalty: config.frequency_penalty,
}),
onMessage(message) {
console.debug('sse message', message)
let data
try {
data = JSON.parse(message)
} catch (error) {
console.debug('json error', error)
return
}
if (
data.choices &&
data.choices.length > 0 &&
data.choices[0] &&
data.choices[0].delta &&
'content' in data.choices[0].delta
) {
answer += data.choices[0].delta.content
port.postMessage({ answer: answer, done: false, session: null })
}
if (data.choices && data.choices.length > 0 && data.choices[0]?.finish_reason) {
pushRecord(session, question, answer)
console.debug('conversation history', { content: session.conversationRecords })
port.postMessage({ answer: null, done: true, session: session })
}
},
async onStart() {},
async onEnd() {
port.postMessage({ done: true })
port.onMessage.removeListener(messageListener)
port.onDisconnect.removeListener(disconnectListener)
},
async onError(resp) {
port.onMessage.removeListener(messageListener)
port.onDisconnect.removeListener(disconnectListener)
if (resp instanceof Error) throw resp
const error = await resp.json().catch(() => ({}))
throw new Error(
!isEmpty(error) ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`,
)
},
},
)
}