1
import OpenAI from 'openai'
2
import { StatusCodes } from 'http-status-codes'
3
import { uniqWith, isEqual, cloneDeep } from 'lodash'
4
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
5
import { Assistant } from '../../database/entities/Assistant'
6
import { Credential } from '../../database/entities/Credential'
7
import { decryptCredentialData, getAppVersion } from '../../utils'
8
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
9
import { getErrorMessage } from '../../errors/utils'
11
const createAssistant = async (requestBody: any): Promise<any> => {
13
const appServer = getRunningExpressApp()
14
if (!requestBody.details) {
15
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Invalid request body`)
17
const assistantDetails = JSON.parse(requestBody.details)
19
const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({
20
id: requestBody.credential
24
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${requestBody.credential} not found`)
27
// Decrpyt credentialData
28
const decryptedCredentialData = await decryptCredentialData(credential.encryptedData)
29
const openAIApiKey = decryptedCredentialData['openAIApiKey']
31
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `OpenAI ApiKey not found`)
33
const openai = new OpenAI({ apiKey: openAIApiKey })
37
if (assistantDetails.tools) {
38
for (const tool of assistantDetails.tools ?? []) {
45
// Save tool_resources to be stored later into database
46
const savedToolResources = cloneDeep(assistantDetails.tool_resources)
48
// Cleanup tool_resources for creating assistant
49
if (assistantDetails.tool_resources) {
50
for (const toolResource in assistantDetails.tool_resources) {
51
if (toolResource === 'file_search') {
52
assistantDetails.tool_resources['file_search'] = {
53
vector_store_ids: assistantDetails.tool_resources['file_search'].vector_store_ids
55
} else if (toolResource === 'code_interpreter') {
56
assistantDetails.tool_resources['code_interpreter'] = {
57
file_ids: assistantDetails.tool_resources['code_interpreter'].file_ids
63
// If the assistant doesn't exist, create a new one
64
if (!assistantDetails.id) {
65
const newAssistant = await openai.beta.assistants.create({
66
name: assistantDetails.name,
67
description: assistantDetails.description,
68
instructions: assistantDetails.instructions,
69
model: assistantDetails.model,
71
tool_resources: assistantDetails.tool_resources,
72
temperature: assistantDetails.temperature,
73
top_p: assistantDetails.top_p
75
assistantDetails.id = newAssistant.id
77
const retrievedAssistant = await openai.beta.assistants.retrieve(assistantDetails.id)
78
let filteredTools = uniqWith([...retrievedAssistant.tools.filter((tool) => tool.type === 'function'), ...tools], isEqual)
79
// Remove empty functions
80
filteredTools = filteredTools.filter((tool) => !(tool.type === 'function' && !(tool as any).function))
82
await openai.beta.assistants.update(assistantDetails.id, {
83
name: assistantDetails.name,
84
description: assistantDetails.description ?? '',
85
instructions: assistantDetails.instructions ?? '',
86
model: assistantDetails.model,
88
tool_resources: assistantDetails.tool_resources,
89
temperature: assistantDetails.temperature,
90
top_p: assistantDetails.top_p
94
const newAssistantDetails = {
97
if (savedToolResources) newAssistantDetails.tool_resources = savedToolResources
99
requestBody.details = JSON.stringify(newAssistantDetails)
101
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error creating new assistant - ${getErrorMessage(error)}`)
103
const newAssistant = new Assistant()
104
Object.assign(newAssistant, requestBody)
106
const assistant = appServer.AppDataSource.getRepository(Assistant).create(newAssistant)
107
const dbResponse = await appServer.AppDataSource.getRepository(Assistant).save(assistant)
109
await appServer.telemetry.sendTelemetry('assistant_created', {
110
version: await getAppVersion(),
111
assistantId: dbResponse.id
115
throw new InternalFlowiseError(
116
StatusCodes.INTERNAL_SERVER_ERROR,
117
`Error: assistantsService.createAssistant - ${getErrorMessage(error)}`
122
const deleteAssistant = async (assistantId: string, isDeleteBoth: any): Promise<any> => {
124
const appServer = getRunningExpressApp()
125
const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({
129
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`)
132
const assistantDetails = JSON.parse(assistant.details)
133
const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({
134
id: assistant.credential
138
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${assistant.credential} not found`)
141
// Decrpyt credentialData
142
const decryptedCredentialData = await decryptCredentialData(credential.encryptedData)
143
const openAIApiKey = decryptedCredentialData['openAIApiKey']
145
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `OpenAI ApiKey not found`)
148
const openai = new OpenAI({ apiKey: openAIApiKey })
149
const dbResponse = await appServer.AppDataSource.getRepository(Assistant).delete({ id: assistantId })
150
if (isDeleteBoth) await openai.beta.assistants.del(assistantDetails.id)
152
} catch (error: any) {
153
if (error.status === 404 && error.type === 'invalid_request_error') {
156
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error deleting assistant - ${getErrorMessage(error)}`)
160
throw new InternalFlowiseError(
161
StatusCodes.INTERNAL_SERVER_ERROR,
162
`Error: assistantsService.deleteAssistant - ${getErrorMessage(error)}`
167
const getAllAssistants = async (): Promise<any> => {
169
const appServer = getRunningExpressApp()
170
const dbResponse = await appServer.AppDataSource.getRepository(Assistant).find()
173
throw new InternalFlowiseError(
174
StatusCodes.INTERNAL_SERVER_ERROR,
175
`Error: assistantsService.getAllAssistants - ${getErrorMessage(error)}`
180
const getAssistantById = async (assistantId: string): Promise<any> => {
182
const appServer = getRunningExpressApp()
183
const dbResponse = await appServer.AppDataSource.getRepository(Assistant).findOneBy({
187
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`)
191
throw new InternalFlowiseError(
192
StatusCodes.INTERNAL_SERVER_ERROR,
193
`Error: assistantsService.getAssistantById - ${getErrorMessage(error)}`
198
const updateAssistant = async (assistantId: string, requestBody: any): Promise<any> => {
200
const appServer = getRunningExpressApp()
201
const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({
206
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`)
209
const openAIAssistantId = JSON.parse(assistant.details)?.id
210
const body = requestBody
211
const assistantDetails = JSON.parse(body.details)
212
const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({
217
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${body.credential} not found`)
220
// Decrpyt credentialData
221
const decryptedCredentialData = await decryptCredentialData(credential.encryptedData)
222
const openAIApiKey = decryptedCredentialData['openAIApiKey']
224
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `OpenAI ApiKey not found`)
227
const openai = new OpenAI({ apiKey: openAIApiKey })
230
if (assistantDetails.tools) {
231
for (const tool of assistantDetails.tools ?? []) {
238
// Save tool_resources to be stored later into database
239
const savedToolResources = cloneDeep(assistantDetails.tool_resources)
241
// Cleanup tool_resources before updating
242
if (assistantDetails.tool_resources) {
243
for (const toolResource in assistantDetails.tool_resources) {
244
if (toolResource === 'file_search') {
245
assistantDetails.tool_resources['file_search'] = {
246
vector_store_ids: assistantDetails.tool_resources['file_search'].vector_store_ids
248
} else if (toolResource === 'code_interpreter') {
249
assistantDetails.tool_resources['code_interpreter'] = {
250
file_ids: assistantDetails.tool_resources['code_interpreter'].file_ids
256
const retrievedAssistant = await openai.beta.assistants.retrieve(openAIAssistantId)
257
let filteredTools = uniqWith([...retrievedAssistant.tools.filter((tool) => tool.type === 'function'), ...tools], isEqual)
258
filteredTools = filteredTools.filter((tool) => !(tool.type === 'function' && !(tool as any).function))
260
await openai.beta.assistants.update(openAIAssistantId, {
261
name: assistantDetails.name,
262
description: assistantDetails.description,
263
instructions: assistantDetails.instructions,
264
model: assistantDetails.model,
265
tools: filteredTools,
266
tool_resources: assistantDetails.tool_resources,
267
temperature: assistantDetails.temperature,
268
top_p: assistantDetails.top_p
271
const newAssistantDetails = {
273
id: openAIAssistantId
275
if (savedToolResources) newAssistantDetails.tool_resources = savedToolResources
277
const updateAssistant = new Assistant()
278
body.details = JSON.stringify(newAssistantDetails)
279
Object.assign(updateAssistant, body)
281
appServer.AppDataSource.getRepository(Assistant).merge(assistant, updateAssistant)
282
const dbResponse = await appServer.AppDataSource.getRepository(Assistant).save(assistant)
285
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error updating assistant - ${getErrorMessage(error)}`)
288
throw new InternalFlowiseError(
289
StatusCodes.INTERNAL_SERVER_ERROR,
290
`Error: assistantsService.updateAssistant - ${getErrorMessage(error)}`