forked from ChatGPTBox-dev/chatGPTBox
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcustom-api.mjs
More file actions
111 lines (104 loc) · 3.35 KB
/
custom-api.mjs
File metadata and controls
111 lines (104 loc) · 3.35 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// custom api version
// There is a lot of duplicated code here, but it is very easy to refactor.
// The current state is mainly convenient for making targeted changes at any time,
// and it has not yet had a negative impact on maintenance.
// If necessary, I will refactor.
import { getUserConfig } from '../../config/index.mjs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { isEmpty } from 'lodash-es'
import { pushRecord, setAbortController } from './shared.mjs'
import { getChatCompletionsTokenParams } from './openai-token-params.mjs'
/**
* @param {Browser.Runtime.Port} port
* @param {string} question
* @param {Session} session
* @param {string} apiUrl
* @param {string} apiKey
* @param {string} modelName
*/
export async function generateAnswersWithCustomApi(
port,
question,
session,
apiUrl,
apiKey,
modelName,
) {
const { controller, messageListener, disconnectListener } = setAbortController(port)
const config = await getUserConfig()
const prompt = getConversationPairs(
session.conversationRecords.slice(-config.maxConversationContextLength),
false,
)
prompt.push({ role: 'user', content: question })
let answer = ''
let finished = false
const finish = () => {
finished = true
pushRecord(session, question, answer)
console.debug('conversation history', { content: session.conversationRecords })
port.postMessage({ answer: null, done: true, session: session })
}
await fetchSSE(apiUrl, {
method: 'POST',
signal: controller.signal,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
messages: prompt,
model: modelName,
stream: true,
...getChatCompletionsTokenParams('custom', modelName, config.maxResponseTokenLength),
temperature: config.temperature,
}),
onMessage(message) {
console.debug('sse message', message)
if (finished) return
if (message.trim() === '[DONE]') {
finish()
return
}
let data
try {
data = JSON.parse(message)
} catch (error) {
console.debug('json error', error)
return
}
if (data.response) answer = data.response
else {
const delta = data.choices?.[0]?.delta?.content
const content = data.choices?.[0]?.message?.content
const text = data.choices?.[0]?.text
if (delta !== undefined) {
answer += delta
} else if (typeof content === 'string') {
answer = content
} else if (text) {
answer += text
}
}
port.postMessage({ answer: answer, done: false, session: null })
if (data.choices?.[0]?.finish_reason) {
finish()
return
}
},
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}`)
},
})
}