2
0

⬆️ (openai) Replace openai-edge with openai and upgrade next

This commit is contained in:
Baptiste Arnaud
2023-10-06 14:22:38 +02:00
parent dfcaa0f1d0
commit 225dfed313
15 changed files with 415 additions and 178 deletions

View File

@@ -105,7 +105,7 @@ export const createChatCompletionOpenAI = async (
}
}
const { response, logs } = await executeChatCompletionOpenAIRequest({
const { chatCompletion, logs } = await executeChatCompletionOpenAIRequest({
apiKey,
messages,
model: options.model,
@@ -113,15 +113,15 @@ export const createChatCompletionOpenAI = async (
baseUrl: options.baseUrl,
apiVersion: options.apiVersion,
})
if (!response)
if (!chatCompletion)
return {
outgoingEdgeId,
logs,
}
const messageContent = response.choices.at(0)?.message?.content
const totalTokens = response.usage?.total_tokens
const messageContent = chatCompletion.choices.at(0)?.message?.content
const totalTokens = chatCompletion.usage?.total_tokens
if (isEmpty(messageContent)) {
console.error('OpenAI block returned empty message', response)
console.error('OpenAI block returned empty message', chatCompletion.choices)
return { outgoingEdgeId, newSessionState }
}
return resumeChatCompletion(newSessionState, {

View File

@@ -2,15 +2,12 @@ import { isNotEmpty } from '@typebot.io/lib/utils'
import { ChatReply } from '@typebot.io/schemas'
import { OpenAIBlock } from '@typebot.io/schemas/features/blocks/integrations/openai'
import { HTTPError } from 'got'
import {
Configuration,
OpenAIApi,
type CreateChatCompletionRequest,
type CreateChatCompletionResponse,
ResponseTypes,
} from 'openai-edge'
import { ClientOptions, OpenAI } from 'openai'
type Props = Pick<CreateChatCompletionRequest, 'messages' | 'model'> & {
type Props = Pick<
OpenAI.Chat.ChatCompletionCreateParams,
'messages' | 'model'
> & {
apiKey: string
temperature: number | undefined
currentLogs?: ChatReply['logs']
@@ -27,38 +24,34 @@ export const executeChatCompletionOpenAIRequest = async ({
isRetrying,
currentLogs = [],
}: Props): Promise<{
response?: CreateChatCompletionResponse
chatCompletion?: OpenAI.Chat.Completions.ChatCompletion
logs?: ChatReply['logs']
}> => {
const logs: ChatReply['logs'] = currentLogs
if (messages.length === 0) return { logs }
try {
const config = new Configuration({
const config = {
apiKey,
basePath: baseUrl,
baseOptions: {
headers: {
'api-key': apiKey,
},
baseURL: baseUrl,
defaultHeaders: {
'api-key': apiKey,
},
defaultQueryParams: isNotEmpty(apiVersion)
? new URLSearchParams({
defaultQuery: isNotEmpty(apiVersion)
? {
'api-version': apiVersion,
})
}
: undefined,
})
} satisfies ClientOptions
const openai = new OpenAIApi(config)
const openai = new OpenAI(config)
const response = await openai.createChatCompletion({
const chatCompletion = await openai.chat.completions.create({
model,
messages,
temperature,
})
const completion =
(await response.json()) as ResponseTypes['createChatCompletion']
return { response: completion, logs }
return { chatCompletion, logs }
} catch (error) {
if (error instanceof HTTPError) {
if (

View File

@@ -7,19 +7,15 @@ import {
} from '@typebot.io/schemas/features/blocks/integrations/openai'
import { SessionState } from '@typebot.io/schemas/features/chat/sessionState'
import { OpenAIStream } from 'ai'
import {
ChatCompletionRequestMessage,
Configuration,
OpenAIApi,
} from 'openai-edge'
import { parseVariableNumber } from '../../../variables/parseVariableNumber'
import { ClientOptions, OpenAI } from 'openai'
export const getChatCompletionStream =
(conn: Connection) =>
async (
state: SessionState,
options: ChatCompletionOpenAIOptions,
messages: ChatCompletionRequestMessage[]
messages: OpenAI.Chat.ChatCompletionMessageParam[]
) => {
if (!options.credentialsId) return
const credentials = (
@@ -41,31 +37,27 @@ export const getChatCompletionStream =
options.advancedSettings?.temperature
)
const config = new Configuration({
const config = {
apiKey,
basePath: options.baseUrl,
baseOptions: {
headers: {
'api-key': apiKey,
},
baseURL: options.baseUrl,
defaultHeaders: {
'api-key': apiKey,
},
defaultQueryParams: isNotEmpty(options.apiVersion)
? new URLSearchParams({
defaultQuery: isNotEmpty(options.apiVersion)
? {
'api-version': options.apiVersion,
})
}
: undefined,
})
} satisfies ClientOptions
const openai = new OpenAIApi(config)
const openai = new OpenAI(config)
const response = await openai.createChatCompletion({
const response = await openai.chat.completions.create({
model: options.model,
temperature,
stream: true,
messages,
})
if (!response.ok) return response
return OpenAIStream(response)
}

View File

@@ -1,7 +1,7 @@
import { byId, isNotEmpty } from '@typebot.io/lib'
import { Variable, VariableWithValue } from '@typebot.io/schemas'
import { ChatCompletionOpenAIOptions } from '@typebot.io/schemas/features/blocks/integrations/openai'
import type { ChatCompletionRequestMessage } from 'openai-edge'
import type { OpenAI } from 'openai'
import { parseVariables } from '../../../variables/parseVariables'
import { transformStringVariablesToList } from '../../../variables/transformVariablesToList'
@@ -11,7 +11,7 @@ export const parseChatCompletionMessages =
messages: ChatCompletionOpenAIOptions['messages']
): {
variablesTransformedToList: VariableWithValue[]
messages: ChatCompletionRequestMessage[]
messages: OpenAI.Chat.ChatCompletionMessageParam[]
} => {
const variablesTransformedToList: VariableWithValue[] = []
const parsedMessages = messages
@@ -47,7 +47,7 @@ export const parseChatCompletionMessages =
variable.id === message.content?.assistantMessagesVariableId
)?.value ?? []) as string[]
let allMessages: ChatCompletionRequestMessage[] = []
let allMessages: OpenAI.Chat.ChatCompletionMessageParam[] = []
if (userMessages.length > assistantMessages.length)
allMessages = userMessages.flatMap((userMessage, index) => [
@@ -56,7 +56,7 @@ export const parseChatCompletionMessages =
content: userMessage,
},
{ role: 'assistant', content: assistantMessages.at(index) ?? '' },
]) satisfies ChatCompletionRequestMessage[]
]) satisfies OpenAI.Chat.ChatCompletionMessageParam[]
else {
allMessages = assistantMessages.flatMap(
(assistantMessage, index) => [
@@ -66,7 +66,7 @@ export const parseChatCompletionMessages =
content: userMessages.at(index) ?? '',
},
]
) satisfies ChatCompletionRequestMessage[]
) satisfies OpenAI.Chat.ChatCompletionMessageParam[]
}
return allMessages
@@ -77,11 +77,11 @@ export const parseChatCompletionMessages =
name: message.name
? parseVariables(variables)(message.name)
: undefined,
} satisfies ChatCompletionRequestMessage
} satisfies OpenAI.Chat.ChatCompletionMessageParam
})
.filter(
(message) => isNotEmpty(message?.role) && isNotEmpty(message?.content)
) as ChatCompletionRequestMessage[]
) as OpenAI.Chat.ChatCompletionMessageParam[]
return {
variablesTransformedToList,

View File

@@ -18,7 +18,7 @@
"@typebot.io/tsconfig": "workspace:*",
"@udecode/plate-common": "^21.1.5",
"@udecode/plate-serializer-md": "^24.4.0",
"ai": "2.1.32",
"ai": "2.2.14",
"chrono-node": "2.6.6",
"date-fns": "^2.30.0",
"google-auth-library": "8.9.0",
@@ -27,7 +27,7 @@
"libphonenumber-js": "1.10.37",
"node-html-parser": "^6.1.5",
"nodemailer": "6.9.3",
"openai-edge": "1.2.2",
"openai": "^4.11.1",
"qs": "^6.11.2",
"remark-slate": "^1.8.6",
"stripe": "12.13.0"

View File

@@ -63,7 +63,7 @@ export const executeClientSideAction = async ({
logs: [
{
status: 'error',
description: 'Failed to stream OpenAI completion',
description: 'OpenAI returned an error',
details: JSON.stringify(error, null, 2),
},
],

View File

@@ -6,7 +6,7 @@
"main": "./env.ts",
"types": "./env.ts",
"dependencies": {
"@t3-oss/env-nextjs": "^0.6.0",
"@t3-oss/env-nextjs": "^0.7.0",
"zod": "3.21.4"
},
"devDependencies": {

View File

@@ -13,7 +13,7 @@
"@typebot.io/schemas": "workspace:*",
"@typebot.io/tsconfig": "workspace:*",
"@types/nodemailer": "6.4.8",
"next": "13.4.3",
"next": "13.5.4",
"nodemailer": "6.9.3",
"typescript": "5.1.6"
},

View File

@@ -62,7 +62,9 @@ export const isNotDefined = <T>(
value: T | undefined | null
): value is undefined | null => value === undefined || value === null
export const isEmpty = (value: string | undefined | null): value is undefined =>
export const isEmpty = (
value: string | undefined | null
): value is undefined | null =>
value === undefined || value === null || value === ''
export const isNotEmpty = (value: string | undefined | null): value is string =>