Files
chatGPTBox/src/services/apis/chatglm-api.mjs
T
AceLam d24958f9a0 Add ChatGLM API (#567)
* Add ChatGLM API

* add minimal build

* a small patch

---------

Co-authored-by: josc146 <josStorer@outlook.com>
2023-12-03 23:31:04 +08:00

116 lines
3.6 KiB
JavaScript

import { Models, getUserConfig } from '../../config/index.mjs'
import { pushRecord, setAbortController } from './shared.mjs'
import { isEmpty } from 'lodash-es'
import { getToken } from '../../utils/jwt-token-generator.mjs'
import { createParser } from '../../utils/eventsource-parser.mjs'
async function fetchSSE(resource, options) {
const { onMessage, onStart, onEnd, onError, ...fetchOptions } = options
const resp = await fetch(resource, fetchOptions).catch(async (err) => {
await onError(err)
})
if (!resp) return
if (!resp.ok) {
await onError(resp)
return
}
const parser = createParser((event) => {
if (event.type === 'event') {
onMessage(event)
}
})
let hasStarted = false
const reader = resp.body.getReader()
let result
while (!(result = await reader.read()).done) {
const chunk = result.value
if (!hasStarted) {
hasStarted = true
await onStart(new TextDecoder().decode(chunk))
}
parser.feed(chunk)
}
await onEnd()
}
/**
* @param {Runtime.Port} port
* @param {string} question
* @param {Session} session
* @param {string} modelName
*/
export async function generateAnswersWithChatGLMApi(port, question, session, modelName) {
const { controller, messageListener, disconnectListener } = setAbortController(port)
const config = await getUserConfig()
const prompt = []
for (const record of session.conversationRecords.slice(-config.maxConversationContextLength)) {
prompt.push({ role: 'user', content: record.question })
prompt.push({ role: 'assistant', content: record.answer })
}
prompt.push({ role: 'user', content: question })
let answer = ''
await fetchSSE(
`https://open.bigmodel.cn/api/paas/v3/model-api/${Models[modelName].value}/sse-invoke`,
{
method: 'POST',
signal: controller.signal,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Accept: 'text/event-stream',
Authorization: getToken(config.chatglmApiKey),
},
body: JSON.stringify({
prompt: prompt,
// temperature: config.temperature,
// top_t: 0.7,
// request_id: string
// incremental: true,
// return_type: "json_string",
// ref: {"enable": "true", "search_query": "history"},
}),
onMessage(event) {
console.debug('sse event', event)
// Handle different types of events
switch (event.event) {
case 'add':
// In the case of an "add" event, append the completion to the answer
if (event.data) {
answer += event.data
port.postMessage({ answer: answer, done: false, session: null })
}
break
case 'error':
case 'interrupted':
case 'finish':
pushRecord(session, question, answer)
console.debug('conversation history', { content: session.conversationRecords })
port.postMessage({ answer: null, done: true, session: session })
break
default:
break
}
},
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}`,
)
},
},
)
}