feat: 流式输出内容 (#93)

* feat: 流式输出内容

* fix: 修复异常状态

* feat: markdown 链接颜色
This commit is contained in:
Redon
2023-02-22 23:03:20 +08:00
committed by GitHub
parent ba83856173
commit 09359c3c46
7 changed files with 150 additions and 43 deletions

View File

@@ -15,6 +15,7 @@
},
"scripts": {
"start": "esno ./src/index.ts",
"dev": "esno watch ./src/index.ts",
"prod": "esno ./build/index.js",
"build": "pnpm clean && tsup",
"clean": "rimraf build",

View File

@@ -1,6 +1,6 @@
import * as dotenv from 'dotenv'
import 'isomorphic-fetch'
import type { ChatGPTAPI, SendMessageOptions } from 'chatgpt'
import type { ChatGPTAPI, ChatMessage, SendMessageOptions } from 'chatgpt'
import { ChatGPTUnofficialProxyAPI } from 'chatgpt'
import { sendResponse } from './utils'
@@ -8,7 +8,7 @@ dotenv.config()
let apiModel: 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined
export interface ChatContext {
interface ChatContext {
conversationId?: string
parentMessageId?: string
}
@@ -65,6 +65,34 @@ async function chatReply(
}
}
async function chatReplyProcess(
message: string,
lastContext?: { conversationId?: string; parentMessageId?: string },
process?: (chat: ChatMessage) => void,
) {
if (!message)
return sendResponse({ type: 'Fail', message: 'Message is empty' })
try {
let options: SendMessageOptions = { timeoutMs }
if (lastContext)
options = { ...lastContext }
const response = await api.sendMessage(message, {
...options,
onProgress: (partialResponse) => {
process?.(partialResponse)
},
})
return sendResponse({ type: 'Success', data: response })
}
catch (error: any) {
return sendResponse({ type: 'Fail', message: error.message })
}
}
async function chatConfig() {
return sendResponse({
type: 'Success',
@@ -76,4 +104,6 @@ async function chatConfig() {
})
}
export { chatReply, chatConfig }
export type { ChatContext, ChatMessage }
export { chatReply, chatReplyProcess, chatConfig }

View File

@@ -1,6 +1,6 @@
import express from 'express'
import type { ChatContext } from './chatgpt'
import { chatConfig, chatReply } from './chatgpt'
import type { ChatContext, ChatMessage } from './chatgpt'
import { chatConfig, chatReply, chatReplyProcess } from './chatgpt'
const app = express()
const router = express.Router()
@@ -26,6 +26,23 @@ router.post('/chat', async (req, res) => {
}
})
router.post('/chat-process', async (req, res) => {
res.setHeader('Content-type', 'application/octet-stream')
try {
const { prompt, options = {} } = req.body as { prompt: string; options?: ChatContext }
await chatReplyProcess(prompt, options, (chat: ChatMessage) => {
res.write(JSON.stringify(chat))
})
}
catch (error) {
res.write(JSON.stringify(error))
}
finally {
res.end()
}
})
router.post('/config', async (req, res) => {
try {
const response = await chatConfig()