Skip to content

Commit

Permalink
update openai
Browse files Browse the repository at this point in the history
  • Loading branch information
SchneeHertz committed Aug 16, 2023
1 parent 9c704e3 commit bddeb0e
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 67 deletions.
62 changes: 14 additions & 48 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ const sound = require('sound-play')
const _ = require('lodash')
const { Configuration, OpenAIApi } = require('openai')

const { config, history, STORE_PATH, LOG_PATH, AUDIO_PATH, SPEECH_AUDIO_PATH } = require('./utils/initFile.js')
const { config, history, STORE_PATH, LOG_PATH, AUDIO_PATH } = require('./utils/initFile.js')
const { getSpeechText } = require('./modules/whisper.js')
const { ttsPromise } = require('./modules/edge-tts.js')
const { openaiChat, openaiChatStream } = require('./modules/common.js')
const {
OPENAI_API_KEY, USE_MODEL,
OPENAI_API_KEY, DEFAULT_MODEL,
SpeechSynthesisVoiceName,
ADMIN_NAME, AI_NAME,
systemPrompt,
proxy
proxyObject
} = config

let logFile = fs.createWriteStream(path.join(LOG_PATH, `log-${new Date().toLocaleString('zh-CN').replace(/[\/:]/gi, '-')}.txt`), {flags: 'w'})
Expand Down Expand Up @@ -107,73 +108,38 @@ const resolveSpeakTextList = async () => {
resolveSpeakTextList()

const resloveAdminPrompt = async ({prompt, triggerRecord})=> {
let context = []
for (let conversation of _.takeRight(history.conversationHistory, history.useHistory)) {
context.push({role: 'user', content: conversation.user})
context.push({role: 'assistant', content: conversation.assistant})
}
messages = [
let messages = [
{role: 'system', content: systemPrompt},
{role: 'user', content: `我和${AI_NAME}的对话内容?`},
{role: 'assistant', content: history.memory},
{role: 'user', content: `我的名字是${ADMIN_NAME}`},
{role: 'assistant', content: `你好, ${ADMIN_NAME}`},
...context,
..._.takeRight(history, 10),
{role: 'user', content: prompt}
]
openai.createChatCompletion({
model: USE_MODEL,
model: DEFAULT_MODEL,
messages,
}, { proxy })
}, { proxyObject })
.then(res=>{
let resText = res.data.choices[0].message.content
history.conversationHistory.push({
user: prompt,
assistant: resText.slice(0, 200)
})
history.conversationHistory = _.takeRight(history.conversationHistory, 20)
history.useHistory += 1
history.push(
{role: 'user', content: prompt},
{role: 'assistant', content: resText}
)
history = _.takeRight(history, 50)
fs.writeFileSync(path.join(STORE_PATH, 'history.json'), JSON.stringify(history, null, ' '), {encoding: 'utf-8'})
if (history.useHistory >= history.limitHistory.conversationLimit) {
updateMemory()
}
messageLogAndSend({
id: nanoid(),
from: triggerRecord ? `(${AI_NAME})` : AI_NAME,
text: resText
})
speechList.push({text: `${resText}`, triggerRecord})
if (triggerRecord) speechList.push({text: `${resText}`, triggerRecord})
})
.catch(e=>{
console.log(e)
STATUS.isSpeechTalk = false
})
}

const updateMemory = ()=>{
let context = []
for (let conversation of _.takeRight(history.conversationHistory, history.useHistory)) {
context.push({role: 'user', content: conversation.user})
context.push({role: 'assistant', content: conversation.assistant})
}
let messages = [
{role: 'system', content: systemPrompt},
{role: 'user', content: `我和${AI_NAME}的对话内容?`},
{role: 'assistant', content: history.memory},
{role: 'user', content: `我的名字是${ADMIN_NAME}`},
{role: 'assistant', content: `你好, ${ADMIN_NAME}`},
...context,
{role: 'user', content: `${ADMIN_NAME}:总结你和我的对话内容,要强调细节`}
]
openai.createChatCompletion({
model: USE_MODEL,
messages
}, { proxy })
.then(async res=>{
history.memory = res.data.choices[0].message.content.slice(0, history.limitHistory.memoryLength)
fs.writeFileSync(path.join(STORE_PATH, 'history.json'), JSON.stringify(history, null, ' '), {encoding: 'utf-8'})
})
}

const triggerSpeech = async ()=>{
STATUS.isRecording = true
Expand Down
163 changes: 163 additions & 0 deletions modules/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
const { StringDecoder } = require('node:string_decoder')
const { Configuration, OpenAIApi } = require('openai')
const axios = require('axios')
const _ = require('lodash')
const { config } = require('../utils/initFile.js')

const {
OPENAI_API_KEY,
AZURE_OPENAI_KEY, AZURE_OPENAI_ENDPOINT, AZURE_API_VERSION,
DEFAULT_MODEL,
proxyObject,
} = config

const configuration = new Configuration({
apiKey: OPENAI_API_KEY
})
const openai = new OpenAIApi(configuration)
const openaiChat = ({ model = DEFAULT_MODEL, messages, functions, function_call, timeoutMs = 40000 }) => {
return openai.createChatCompletion({
model, messages, functions, function_call,
presence_penalty: 0.2,
frequency_penalty: 0.2
}, {
timeout: timeoutMs,
proxy: proxyObject
})
}
const openaiChatStream = async function* ({ model = DEFAULT_MODEL, messages, timeoutMs = 20000 }) {
const response = await openai.createChatCompletion(
{
model, messages,
presence_penalty: 0.2,
frequency_penalty: 0.2,
stream: true,
},
{
timeout: timeoutMs,
proxy: proxyObject,
responseType: 'stream',
},
)

for await (const chunk of response.data) {
const lines = chunk
.toString('utf8')
.split('\n')
.filter((line) => line.trim().startsWith('data: '))

for (const line of lines) {
const message = line.replace(/^data: /, '')
if (message === '[DONE]') {
return
}

const json = JSON.parse(message)
const token = _.get(json, 'choices[0].delta.content')
const functionName = _.get(json, 'choices[0].delta.function_call.name')
if (functionName) console.log('!!!second function call ' + functionName)
if (token) {
yield token
}
}
}
}

const openaiEmbedding = ({ input, model = 'text-embedding-ada-002', timeoutMs = 20000 })=>{
return openai.createEmbedding({
model, input
}, {
timeout: timeoutMs,
proxy: proxyObject
})
.then(res => {
return _.get(res, 'data.data[0].embedding')
})
}

const azureOpenaiChat = ({ model = DEFAULT_MODEL, messages, timeoutMs = 40000 }) => {
model = model.replace('.', '')
return axios.post(
`${AZURE_OPENAI_ENDPOINT}/openai/deployments/${model}/chat/completions?api-version=${AZURE_API_VERSION}`,
{ messages },
{
timeout: timeoutMs,
headers: {
'Content-Type': 'application/json',
'api-key': AZURE_OPENAI_KEY,
},
proxy: proxyObject
}
)
}
const azureOpenaiChatStream = async function* ({ model = DEFAULT_MODEL, messages, timeoutMs = 20000 }) {
model = model.replace('.', '')
let response = await axios.post(
`${AZURE_OPENAI_ENDPOINT}/openai/deployments/${model}/chat/completions?api-version=${AZURE_API_VERSION}`,
{
messages, stream: true
},
{
timeout: timeoutMs,
headers: {
'Content-Type': 'application/json',
'api-key': AZURE_OPENAI_KEY,
},
proxy: proxyObject,
responseType: 'stream'
}
)
const decoder = new StringDecoder('utf8')
let brokeJson = null
for await (const chunk of response.data) {
let lines = decoder.write(chunk)
if (brokeJson !== null) {
lines = brokeJson + lines
brokeJson = null
}
lines = lines.split('\n').filter((line) => line.trim().startsWith('data: '))

for (const line of lines) {
const message = line.replace(/^data: /, '')
if (message === '[DONE]') {
return
}
try {
const json = JSON.parse(message)
const token = _.get(json, 'choices[0].delta.content')
if (token) {
yield token
}
} catch {
brokeJson = 'data: ' + message
}
}
}
}

const azureOpenaiEmbedding = ({ input, model = 'text-embedding-ada-002', timeoutMs = 20000 })=>{
return axios.post(
`${AZURE_OPENAI_ENDPOINT}/openai/deployments/${model}/embeddings?api-version=${AZURE_API_VERSION}`,
{ input },
{
timeout: timeoutMs,
headers: {
'Content-Type': 'application/json',
'api-key': AZURE_OPENAI_KEY,
},
proxy: proxyObject
}
).then(res => {
return _.get(res, 'data.data[0].embedding')
})
}


module.exports = {
openaiChat,
openaiChatStream,
openaiEmbedding,
azureOpenaiChat,
azureOpenaiChatStream,
azureOpenaiEmbedding
}
53 changes: 43 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "chat-xiuliu",
"private": true,
"version": "1.1.0",
"version": "2.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
Expand Down Expand Up @@ -39,6 +39,7 @@
"vue": "^3.2.45"
},
"dependencies": {
"axios": "^1.4.0",
"highlight.js": "^11.8.0",
"highlightjs-copy": "^1.0.4",
"lodash": "^4.17.21",
Expand Down

0 comments on commit bddeb0e

Please sign in to comment.