Skip to content

Commit

Permalink
update to 1106
Browse files Browse the repository at this point in the history
  • Loading branch information
SchneeHertz committed Nov 7, 2023
1 parent c50a28b commit 2caba5b
Show file tree
Hide file tree
Showing 8 changed files with 496 additions and 217 deletions.
2 changes: 2 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ declare module 'vue' {
NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid']
NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NList: typeof import('naive-ui')['NList']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NPopover: typeof import('naive-ui')['NPopover']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']
NSwitch: typeof import('naive-ui')['NSwitch']
Expand Down
165 changes: 109 additions & 56 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,35 @@ const messageLog = (message) => {
logFile.write(format(new Date().toLocaleString('zh-CN'), JSON.stringify(message)) + '\n')
}
const messageSend = (message) => {
// The part of Vision is not accurately calculated in the token calculation.
if (message.countToken) {
let tokenCount = 0
message.messages.forEach((item) => {
tokenCount += getTokenLength(item.content || JSON.stringify(item.function_call))
switch (item.role) {
case 'system':
case 'tool':
tokenCount += getTokenLength(item.content)
break
case 'assistant':
tokenCount += getTokenLength(item.content || JSON.stringify(item.tool_calls))
break
case 'user':
if (typeof item.content === 'string') {
tokenCount += getTokenLength(item.content)
} else {
item.content.forEach((content) => {
switch (content.type) {
case 'text':
tokenCount += getTokenLength(content.text)
break
case 'image_url':
tokenCount += 85
break
}
})
}
break
}
})
tokenCount += getTokenLength(message.text)
message.tokenCount = tokenCount
Expand Down Expand Up @@ -264,57 +289,61 @@ const addHistory = (lines) => {
}

const useOpenaiChatStreamFunction = useAzureOpenai ? azureOpenaiChatStream : openaiChatStream
const resolveMessages = async ({ resArgument, resFunction, resText, resTextTemp, messages, from, round }) => {
const resolveMessages = async ({ resToolCalls, resText, resTextTemp, messages, from, useFunctionCalling = false }) => {

console.log(`use ${useAzureOpenai ? AZURE_CHAT_MODEL : DEFAULT_MODEL}`)

let clientMessageId = nanoid()
let speakIndex = STATUS.speakIndex
STATUS.speakIndex += 1

if (!resText && resFunction && resArgument) {
let functionCallResult
try {
if (!resText && !_.isEmpty(resToolCalls)) {
messageLogAndSend({
id: nanoid(),
from,
messages,
countToken: true,
text: 'use Function Calling'
})
messages.push({ role: 'assistant', content: null, tool_calls: resToolCalls })
addHistory([{ role: 'assistant', content: null, tool_calls: resToolCalls }])
for (let toolCall of resToolCalls) {
let functionCallResult
try {
messageLogAndSend({
id: nanoid(),
from,
text: functionAction[toolCall.function.name](JSON.parse(toolCall.function.arguments))
})
switch (toolCall.function.name) {
case 'getHistoricalConversationContent':
functionCallResult = await functionList[toolCall.function.name](_.assign({ dbTable: memoryTable }, JSON.parse(toolCall.function.arguments)))
break
default:
functionCallResult = await functionList[toolCall.function.name](JSON.parse(toolCall.function.arguments))
break
}
} catch (e) {
console.log(e)
functionCallResult = e.message
}
messages.push({ role: 'tool', tool_call_id: toolCall.id, content: functionCallResult + '' })
addHistory([{ role: 'tool', tool_call_id: toolCall.id, content: functionCallResult + '' }])
console.log({ role: 'tool', tool_call_id: toolCall.id, content: functionCallResult + '' })
messageLogAndSend({
id: nanoid(),
from,
messages,
countToken: true,
text: functionAction[resFunction](JSON.parse(resArgument))
from: 'Function Calling',
text: functionCallResult + ''
})
switch (resFunction) {
case 'getHistoricalConversationContent':
functionCallResult = await functionList[resFunction](_.assign({ dbTable: memoryTable }, JSON.parse(resArgument)))
break
default:
functionCallResult = await functionList[resFunction](JSON.parse(resArgument))
break
}
} catch (e) {
console.log(e)
functionCallResult = e.message
}
let functionCalling = [
{ role: 'assistant', content: null, function_call: { name: resFunction, arguments: resArgument } },
{ role: 'function', name: resFunction, content: functionCallResult + '' }
]
messages.push(...functionCalling)
addHistory(functionCalling)
console.log(functionCalling)
messageLogAndSend({
id: nanoid(),
from: 'Function Calling',
text: functionCallResult + ''
})
}
resFunction = ''
resArgument = ''
resToolCalls = []

let prepareChatOption = { messages }

if (round < functionCallingRoundLimit) {
prepareChatOption.functions = functionInfo
prepareChatOption.function_call = 'auto'
if (useFunctionCalling) {
prepareChatOption.tools = functionInfo
prepareChatOption.tool_choice = 'auto'
}

for await (const { token, f_token } of useOpenaiChatStreamFunction(prepareChatOption)) {
Expand Down Expand Up @@ -343,9 +372,20 @@ const resolveMessages = async ({ resArgument, resFunction, resText, resTextTemp,
}
}
}
let { name, arguments: arg } = f_token
if (name) resFunction = name
if (arg) resArgument += arg
if (!_.isEmpty(f_token)) console.log(f_token)
let [{ index, id, type, function: { name, arguments: arg} } = { function: {} }] = f_token
if (index !== undefined ) {
if (resToolCalls[index]) {
if (id) resToolCalls[index].id = id
if (type) resToolCalls[index].type = type
if (name) resToolCalls[index].function.name = name
if (arg) resToolCalls[index].function.arguments += arg
} else {
resToolCalls[index] = {
id, type, function: { name, arguments: arg }
}
}
}
}

if (STATUS.isAudioPlay) {
Expand All @@ -369,8 +409,7 @@ const resolveMessages = async ({ resArgument, resFunction, resText, resTextTemp,

return {
messages,
resFunction,
resArgument,
resToolCalls,
resTextTemp,
resText
}
Expand All @@ -384,7 +423,7 @@ const resolveMessages = async ({ resArgument, resFunction, resText, resTextTemp,
* @param {Object} options.triggerRecord - The trigger record object.
* @return {Promise<void>} - A promise that resolves with the generated response.
*/
const resloveAdminPrompt = async ({ prompt, triggerRecord, givenSystemPrompt }) => {
const resloveAdminPrompt = async ({ prompt, promptType = 'string', triggerRecord, givenSystemPrompt }) => {
let from = triggerRecord ? `(${AI_NAME})` : AI_NAME
let history = getStore('history')
let messages = [
Expand All @@ -404,16 +443,20 @@ const resloveAdminPrompt = async ({ prompt, triggerRecord, givenSystemPrompt })

let resTextTemp = ''
let resText = ''
let resFunction
let resArgument = ''
let resToolCalls = []

try {
let round = 0
while (resText === '') {
;({ messages, resArgument, resFunction, resText, resTextTemp } = await resolveMessages({
resArgument, resFunction, resText, resTextTemp, messages, from, round
}))
round += 1
if (promptType === 'string') {
let round = 0
while (resText === '') {
let useFunctionCalling = round > functionCallingRoundLimit ? false : true
;({ messages, resToolCalls, resText, resTextTemp } = await resolveMessages({
resToolCalls, resText, resTextTemp, messages, from, useFunctionCalling
}))
round += 1
}
} else {
resText = (await resolveMessages({ resText, messages, from })).resText
}
messageLog({
id: nanoid(),
Expand Down Expand Up @@ -452,15 +495,21 @@ const sendHistory = (limit) => {
case 'assistant':
let text = ''
try {
text = item.content || functionAction[item.function_call.name](JSON.parse(item.function_call.arguments))
} catch {}
if (item.content) {
text = item.content
} else {
text = item.tool_calls.map( item => {
return functionAction[item.function_call.name](JSON.parse(item.function_call.arguments))
}).join('\n')
}
} catch {}
messageSend({
id: nanoid(),
from: AI_NAME,
text
})
break
case 'function':
case 'tool':
messageSend({
id: nanoid(),
from: 'Function Calling',
Expand Down Expand Up @@ -496,8 +545,12 @@ const triggerSpeech = async () => {
}
}

ipcMain.handle('send-prompt', async (event, text) => {
resloveAdminPrompt({ prompt: text })
ipcMain.handle('send-prompt', async (event, prompt) => {
console.log('prompt', prompt)
resloveAdminPrompt({
prompt: prompt.content,
promptType: prompt.type
})
})
ipcMain.handle('get-admin-name', async () => {
return ADMIN_NAME
Expand Down
17 changes: 10 additions & 7 deletions modules/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ const openai = new OpenAI({
})


const openaiChat = ({ model = DEFAULT_MODEL, messages, functions, function_call }) => {
const openaiChat = ({ model = DEFAULT_MODEL, messages, tools, tool_choice }) => {
return openai.chat.completions.create({
model, messages, functions, function_call,
model, messages, tools, tool_choice,
max_tokens: 4096,
})
}

Expand All @@ -36,23 +37,25 @@ const openaiChat = ({ model = DEFAULT_MODEL, messages, functions, function_call
* - messages {array}: An array of message objects representing the conversation.
* @return {generator} A generator that yields tokens from the chat stream.
*/
const openaiChatStream = async function* ({ model = DEFAULT_MODEL, messages, functions, function_call }) {
const openaiChatStream = async function* ({ model = DEFAULT_MODEL, messages, tools, tool_choice }) {
let response
if (functions) {
if (tools) {
response = await openai.chat.completions.create({
model, messages, functions, function_call,
model, messages, tools, tool_choice,
stream: true,
max_tokens: 4096,
})
} else {
response = await openai.chat.completions.create({
model, messages,
stream: true,
max_tokens: 4096,
})
}
for await (const part of response) {
if (['stop', 'function_call'].includes(_.get(part, 'choices[0].delta.finish_reason'))) return
if (['stop', 'tool_calls'].includes(_.get(part, 'choices[0].delta.finish_reason'))) return
const token = _.get(part, 'choices[0].delta.content')
const f_token = _.get(part, 'choices[0].delta.function_call', {})
const f_token = _.get(part, 'choices[0].delta.tool_calls', [])
if (token || !_.isEmpty(f_token)) yield { token, f_token }
}
}
Expand Down
7 changes: 6 additions & 1 deletion modules/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ const functionInfo = [
"required": ["type"],
}
}
]
].map(f => {
return {
type: 'function',
function: f
}
})

if (allowPowerfulInterpreter) {
let findExistInterpreter = functionInfo.findIndex(f => f.name === 'javaScriptInterpreter')
Expand Down

0 comments on commit 2caba5b

Please sign in to comment.