UNPKG

n8n-nodes-openai-analytics

Version:
1,198 lines 125 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIAnalytics = void 0; const openai_1 = __importDefault(require("openai")); const openai_2 = require("./helpers/openai"); const thread_1 = require("./actions/thread"); const assistant_1 = require("./actions/assistant"); const file_1 = require("./actions/file"); const text_1 = require("./actions/text"); const embedding_1 = require("./actions/embedding"); const report_1 = require("./actions/report"); // Assistant API에서 사용할 loadOptions 메서드 정의 const loadOptions = { // Assistant 목록을 로드하는 메서드 async getAssistants() { // OpenAI API 옵션 초기화 const openaiOptions = {}; let credentials; try { const authentication = this.getNodeParameter('authentication', 'openAIAnalyticsApi'); if (authentication === 'openAIAnalyticsApi') { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } else { credentials = await this.getCredentials('openAiApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organization) { openaiOptions.organization = credentials.organization; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } } catch (error) { // 자격 증명 로드 오류 시 기본값 시도 try { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } catch (error) { console.error('Error loading credentials:', error); return [{ name: 'Error loading credentials', value: '' }]; } } const openai = new openai_1.default(openaiOptions); // Assistants 목록 가져오기 try { const assistantsList = await openai.beta.assistants.list({ limit: 100, }); if (!assistantsList.data || assistantsList.data.length === 0) { return [{ name: 'No assistants found', value: '' }]; } // 이름과 ID를 포함한 옵션 목록 생성 const options = assistantsList.data.map((assistant) => ({ name: assistant.name || `Assistant (${assistant.id})`, value: assistant.id, })); return options; } catch (error) { console.error('Error loading assistants:', error); return [{ name: 'Error loading assistants', value: '' }]; } }, // 파일 목록을 로드하는 메서드 async getFiles() { const options = this.getNodeParameter('downloadFilePurpose', 'all'); let purpose; // 파일 목적에 따라 쿼리 파라미터 설정 if (options && options !== 'all') { purpose = options; } // OpenAI API 클라이언트 초기화 const openaiCredentials = await this.getCredentials('openAiApi'); const openaiOptions = { apiKey: openaiCredentials.apiKey, }; // 조직이 설정된 경우 추가 if (openaiCredentials.organization) { openaiOptions.organization = openaiCredentials.organization; } // 기본 URL이 설정된 경우 추가 if (openaiCredentials.baseURL) { openaiOptions.baseURL = openaiCredentials.baseURL; } const openai = new openai_1.default(openaiOptions); try { // 파일 목록 가져오기 const response = await openai.files.list(purpose ? { purpose } : {}); // 옵션 배열로 변환 return response.data.map((file) => ({ name: `${file.filename} (${file.id})`, value: file.id, description: `Purpose: ${file.purpose}, Size: ${Math.round(file.bytes / 1024)} KB`, })); } catch (error) { console.error('Error loading files:', error); return [{ name: 'Error loading files', value: '' }]; } }, // 임베딩 모델 목록을 로드하는 메서드 async getEmbeddingModels() { // OpenAI API 옵션 초기화 const openaiOptions = {}; let credentials; try { const authentication = this.getNodeParameter('authentication', 'openAIAnalyticsApi'); if (authentication === 'openAIAnalyticsApi') { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } else { credentials = await this.getCredentials('openAiApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organization) { openaiOptions.organization = credentials.organization; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } } catch (error) { // 자격 증명 로드 오류 시 기본값 시도 try { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } catch (error) { console.error('Error loading credentials:', error); return [{ name: 'Error loading credentials', value: '' }]; } } const openai = new openai_1.default(openaiOptions); // 모델 목록 가져오기 try { const modelsList = await openai.models.list(); if (!modelsList.data || modelsList.data.length === 0) { return [{ name: 'No models found', value: '' }]; } // 임베딩 모델만 필터링 - 더 정확한 임베딩 모델 필터링 const embeddingModels = modelsList.data.filter((model) => (model.id.includes('embedding') || model.id.includes('embed') || model.id.startsWith('text-embedding'))); // 기본 임베딩 모델 (항상 표시) const defaultEmbeddingModels = [ { name: 'text-embedding-3-small', value: 'text-embedding-3-small', description: '최신 임베딩 모델, 1536 차원' }, { name: 'text-embedding-3-large', value: 'text-embedding-3-large', description: '최고 성능 임베딩 모델, 3072 차원' }, { name: 'text-embedding-ada-002', value: 'text-embedding-ada-002', description: '이전 세대 임베딩 모델, 1536 차원' }, ]; if (embeddingModels.length === 0) { // 임베딩 모델이 없으면 기본 모델 목록만 제공 return defaultEmbeddingModels; } // 이름과 ID를 포함한 옵션 목록 생성 let options = embeddingModels.map((model) => ({ name: model.id, value: model.id, description: getEmbeddingModelDescription(model.id), })); // 모델 정렬: 최신 모델이 위에 오도록 options.sort((a, b) => { // text-embedding-3 모델이 가장 위에 if (a.value.includes('text-embedding-3') && !b.value.includes('text-embedding-3')) return -1; if (!a.value.includes('text-embedding-3') && b.value.includes('text-embedding-3')) return 1; // 그 다음으로 ada-002 모델 if (a.value.includes('ada-002') && !b.value.includes('ada-002')) return -1; if (!a.value.includes('ada-002') && b.value.includes('ada-002')) return 1; // 그 외는 알파벳 순서로 return a.name.localeCompare(b.name); }); // 기본 모델이 없으면 추가 for (const defaultModel of defaultEmbeddingModels) { if (!options.some(option => option.value === defaultModel.value)) { options.unshift(defaultModel); } } // 중복 제거 const uniqueOptions = options.filter((option, index, self) => index === self.findIndex((t) => t.value === option.value)); return uniqueOptions; } catch (error) { console.error('Error loading embedding models:', error); // 오류 시 기본 임베딩 모델 제공 return [ { name: 'text-embedding-3-small', value: 'text-embedding-3-small', description: '최신 임베딩 모델, 1536 차원' }, { name: 'text-embedding-3-large', value: 'text-embedding-3-large', description: '최고 성능 임베딩 모델, 3072 차원' }, { name: 'text-embedding-ada-002', value: 'text-embedding-ada-002', description: '이전 세대 임베딩 모델, 1536 차원' }, ]; } // 임베딩 모델 설명을 반환하는 헬퍼 함수 function getEmbeddingModelDescription(modelId) { if (modelId === 'text-embedding-3-small') return '최신 임베딩 모델, 1536 차원'; if (modelId === 'text-embedding-3-large') return '최고 성능 임베딩 모델, 3072 차원'; if (modelId === 'text-embedding-ada-002') return '이전 세대 임베딩 모델, 1536 차원'; if (modelId.includes('text-embedding-3')) return '최신 세대 임베딩 모델'; if (modelId.includes('ada')) return '이전 세대 임베딩 모델'; return '임베딩 모델'; } }, // 완성 모델 목록을 로드하는 메서드 async getCompletionModels() { // OpenAI API 옵션 초기화 const openaiOptions = {}; let credentials; try { const authentication = this.getNodeParameter('authentication', 'openAIAnalyticsApi'); if (authentication === 'openAIAnalyticsApi') { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } else { credentials = await this.getCredentials('openAiApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organization) { openaiOptions.organization = credentials.organization; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } } catch (error) { // 자격 증명 로드 오류 시 기본값 시도 try { credentials = await this.getCredentials('openAIAnalyticsApi'); openaiOptions.apiKey = credentials.apiKey; if (credentials.organizationId) { openaiOptions.organization = credentials.organizationId; } if (credentials.baseUrl) { openaiOptions.baseURL = credentials.baseUrl; } else { openaiOptions.baseURL = 'https://api.openai.com/v1'; } } catch (error) { console.error('Error loading credentials:', error); return [{ name: 'Error loading credentials', value: '' }]; } } const openai = new openai_1.default(openaiOptions); // 모델 목록 가져오기 try { const modelsList = await openai.models.list(); if (!modelsList.data || modelsList.data.length === 0) { return [{ name: 'No models found', value: '' }]; } // 완성 모델 필터링 (GPT 계열) const completionModels = modelsList.data.filter((model) => model.id.includes('gpt') && !model.id.includes('embedding') && !model.id.includes('search')); if (completionModels.length === 0) { // 완성 모델이 없으면 기본 모델 목록 제공 return [ { name: 'GPT-4.1 (gpt-4-1106-preview)', value: 'gpt-4-1106-preview' }, { name: 'GPT-4o Mini', value: 'gpt-4o-mini' }, { name: 'GPT-4o', value: 'gpt-4o' }, { name: 'GPT-4 Turbo', value: 'gpt-4-turbo' }, { name: 'GPT-4', value: 'gpt-4' }, { name: 'GPT-3.5 Turbo', value: 'gpt-3.5-turbo' }, ]; } // 이름과 ID를 포함한 옵션 목록 생성 const options = completionModels.map((model) => ({ name: model.id, value: model.id, })); // 모델 이름으로 정렬 options.sort((a, b) => a.name.localeCompare(b.name)); // 특정 모델들을 리스트의 맨 위로 이동 (우선순위 모델) const gpt41 = 'gpt-4-1106-preview'; const gpt4o = 'gpt-4o'; const gpt4oMini = 'gpt-4o-mini'; // 특정 모델이 없으면 추가 const hasGpt41 = options.some(option => option.value === gpt41); const hasGpt4o = options.some(option => option.value === gpt4o); const hasGpt4oMini = options.some(option => option.value === gpt4oMini); // 없는 모델 추가 if (!hasGpt41) options.push({ name: 'GPT-4.1 (gpt-4-1106-preview)', value: gpt41 }); if (!hasGpt4o) options.push({ name: 'GPT-4o', value: gpt4o }); if (!hasGpt4oMini) options.push({ name: 'GPT-4o Mini', value: gpt4oMini }); // 우선순위 모델 찾아서 맨 위로 이동 const priorityModels = [gpt41, gpt4o, gpt4oMini]; const prioritizedOptions = []; // 우선순위 모델 순서대로 맨 위로 이동 for (const modelId of priorityModels) { const modelIndex = options.findIndex(option => option.value === modelId); if (modelIndex !== -1) { // 찾은 모델을 복사 let modelOption = options.splice(modelIndex, 1)[0]; // GPT-4.1에는 이름 수정 if (modelId === gpt41 && modelOption.name === gpt41) { modelOption = { name: 'GPT-4.1 (gpt-4-1106-preview)', value: gpt41 }; } prioritizedOptions.push(modelOption); } } // 우선순위 모델과 나머지 모델 합치기 return [...prioritizedOptions, ...options]; } catch (error) { console.error('Error loading completion models:', error); // 오류 시 기본 완성 모델 제공 return [ { name: 'gpt-4o-mini', value: 'gpt-4o-mini' }, { name: 'gpt-4o', value: 'gpt-4o' }, { name: 'gpt-4', value: 'gpt-4' }, { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, ]; } }, }; class OpenAIAnalytics { constructor() { this.description = { displayName: 'OpenAI Analytics', name: 'openAIAnalytics', icon: 'file:openai-analytics.svg', group: ['transform'], version: 1, subtitle: '={{ $parameter["operation"] + ": " + $parameter["resource"] }}', description: 'Use OpenAI Analytics API', defaults: { name: 'OpenAI Analytics', }, inputs: [{ type: 'main', }], outputs: [{ type: 'main', }], credentials: [ { name: 'openAIAnalyticsApi', required: true, displayOptions: { show: { authentication: [ 'openAIAnalyticsApi', ], }, }, }, { name: 'openAiApi', required: true, displayOptions: { show: { authentication: [ 'openAiApi', ], }, }, }, ], properties: [ { displayName: 'Authentication', name: 'authentication', type: 'options', options: [ { name: 'OpenAI Analytics API', value: 'openAIAnalyticsApi', description: 'Use dedicated OpenAI Analytics API credentials', }, { name: 'OpenAI API', value: 'openAiApi', description: 'Use existing OpenAI API credentials', }, ], default: 'openAIAnalyticsApi', }, { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Assistant', value: 'assistant', }, { name: 'Embedding', value: 'embedding', }, { name: 'File', value: 'file', }, { name: 'Report', value: 'report', }, { name: 'Text', value: 'text', }, { name: 'Thread', value: 'thread', }, ], default: 'assistant', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['thread'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new thread', action: 'Create a thread', }, { name: 'Add Message', value: 'addMessage', description: 'Add a message to a thread', action: 'Add a message to a thread', }, { name: 'Run Thread', value: 'run', description: 'Run a thread', action: 'Run a thread', }, { name: 'Check Run Status', value: 'checkRunStatus', description: 'Check the status of a run', action: 'Check the status of a run', }, { name: 'List Messages', value: 'listMessages', description: 'Get messages from a thread', action: 'Get messages from a thread', }, { name: 'Get Thread', value: 'getThread', description: 'Get a thread by ID', action: 'Get a thread', }, { name: 'Create and Run Thread', value: 'createAndRunThread', description: '한 번에 Thread 생성, 메시지 추가, 실행 및 결과 대기', action: 'Create run and wait for thread results', }, { name: 'Run Existing Thread', value: 'runExistingThread', description: '기존 Thread에 메시지 추가, 실행 및 결과 대기', action: 'Run and wait for existing thread results', }, ], default: 'create', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['assistant'], }, }, options: [ { name: 'Get Assistants', value: 'getAssistants', description: 'Get a list of assistants', action: 'Get a list of assistants', }, { name: 'Create Assistant', value: 'createAssistant', description: 'Create a new assistant', action: 'Create a new assistant', } ], default: 'getAssistants', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['file'], }, }, options: [ { name: 'Get Files', value: 'getFiles', description: 'Get a list of files', action: 'Get a list of files', }, { name: 'Get File', value: 'getFile', description: 'Get a file by ID', action: 'Get a file', }, { name: 'Upload File', value: 'uploadFile', description: 'Upload a file to OpenAI', action: 'Upload a file to OpenAI', }, { name: 'Download File', value: 'downloadFile', description: 'Download content of a file', action: 'Download content of a file', }, ], default: 'getFiles', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['report'], }, }, options: [ { name: 'Generate HTML Report', value: 'generateHtmlReport', description: 'Generate an HTML report from text data', action: 'Generate HTML report', }, ], default: 'generateHtmlReport', }, // Thread Create Operation { displayName: 'Initial Message', name: 'initialMessage', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['create'], }, }, default: '', description: 'The initial message to add to the thread (optional)', required: false, }, // Thread Add Message Operation { displayName: 'Thread ID', name: 'threadId', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['addMessage', 'run', 'checkRunStatus', 'listMessages'], }, }, default: '', description: 'The ID of the thread', required: true, }, { displayName: 'Message Role', name: 'messageRole', type: 'options', displayOptions: { show: { resource: ['thread'], operation: ['addMessage'], }, }, options: [ { name: 'User', value: 'user', description: 'A message created by the user', }, ], default: 'user', description: 'The role of the entity that is creating the message', required: true, }, { displayName: 'Message Content', name: 'messageContent', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['addMessage'], }, }, default: '', description: 'The content of the message to add to the thread', required: true, }, { displayName: 'File IDs', name: 'fileIds', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['addMessage'], }, }, default: '', description: 'Comma-separated list of file IDs to attach to the message', required: false, }, // Thread Run Operation { displayName: 'Select Assistant', name: 'threadAssistantSelection', type: 'options', options: [ { name: 'From List', value: 'fromList', description: 'Select an assistant from the list', }, { name: 'By ID', value: 'byId', description: 'Enter the ID of the assistant', }, ], displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], }, }, default: 'fromList', description: 'How to select the assistant', required: true, }, { displayName: 'Assistant', name: 'threadAssistantId', type: 'options', typeOptions: { loadOptionsMethod: 'getAssistants', }, displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], threadAssistantSelection: ['fromList'], }, }, default: '', description: 'Select the assistant to use for this run', required: true, }, { displayName: 'Assistant ID', name: 'threadAssistantId', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], threadAssistantSelection: ['byId'], }, }, default: '', description: 'The ID of the assistant to use for the run', required: true, }, { displayName: 'Wait for Completion', name: 'threadWaitForCompletion', type: 'boolean', displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], }, }, default: true, description: 'Whether to wait for the run to complete before returning', }, { displayName: 'Maximum Poll Time (Seconds)', name: 'threadMaxPollTime', type: 'number', displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], threadWaitForCompletion: [true], }, }, default: 120, description: 'Maximum time in seconds to wait for the run to complete', }, { displayName: 'Instructions', name: 'threadInstructions', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], }, }, default: '', description: 'Override the default system instructions of the assistant', required: false, }, { displayName: 'Simplify Output', name: 'threadSimplifyOutput', type: 'boolean', displayOptions: { show: { resource: ['thread'], operation: ['run', 'createAndRun'], }, }, default: true, description: 'Whether to return simplified response format', hint: '간단한 응답 형식으로 반환할지 여부', }, // Check Run Status Operation { displayName: 'Run ID', name: 'runId', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['checkRunStatus'], }, }, default: '', description: 'The ID of the run', required: true, }, // Create and Run Thread Operation { displayName: 'Message Input Method', name: 'threadMessageInputMethod', type: 'options', options: [ { name: 'Single Message', value: 'singleMessage', description: 'Add only one message', }, { name: 'Multiple Messages', value: 'multipleMessages', description: 'Add multiple messages (can specify role)', }, ], displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], }, }, default: 'singleMessage', description: 'Select message input method', hint: '메시지 입력 방식 선택', }, { displayName: 'Initial Message', name: 'threadInitialMessage', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadMessageInputMethod: ['singleMessage'], }, }, default: '', description: 'The initial message to add to the thread', hint: 'Thread에 추가할 초기 메시지', required: true, }, { displayName: 'Messages', name: 'threadMessages', type: 'fixedCollection', typeOptions: { multipleValues: true, sortable: true, }, displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadMessageInputMethod: ['multipleMessages'], }, }, default: { values: [ { role: 'user', content: '', }, ], }, options: [ { displayName: 'Values', name: 'values', values: [ { displayName: 'Role', name: 'role', type: 'options', options: [ { name: 'User', value: 'user', description: 'User message', }, { name: 'System', value: 'system', description: 'System message', }, ], default: 'user', description: 'Role of the message author', hint: '메시지 작성자의 역할', }, { displayName: 'Content', name: 'content', type: 'string', default: '', description: 'Message content', hint: '메시지 내용', required: true, }, ], }, ], description: 'List of messages to add to the thread', hint: 'Thread에 추가할 메시지 목록', }, { displayName: 'File Attachment Method', name: 'threadFileAttachmentMethod', type: 'options', options: [ { name: 'Use Existing File IDs', value: 'existingFiles', description: 'Use file IDs already uploaded to OpenAI', }, { name: 'Upload Files from Previous Node', value: 'uploadFiles', description: 'Upload binary files from previous node', }, { name: 'Use Both Methods', value: 'both', description: 'Use both existing file IDs and upload new files', }, { name: 'No File Attachments', value: 'none', description: 'Do not attach any files', }, ], displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], }, }, default: 'none', description: 'Select file attachment method', hint: '파일을 첨부하는 방식 선택', }, { displayName: 'Binary Property', name: 'threadBinaryPropertyName', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadFileAttachmentMethod: ['uploadFiles', 'both'], }, }, default: 'data', description: 'Binary property containing data from previous node (e.g. "data")', hint: '이전 노드에서 전달된 바이너리 데이터를 포함하는 속성 이름 (예: "data")', required: true, }, { displayName: 'File Purpose', name: 'threadUploadFilePurpose', type: 'options', options: [ { name: 'Assistants', value: 'assistants', description: 'Files for use with Assistant', }, { name: 'Assistants Input', value: 'assistants_input', description: 'Files for input to Assistant', }, ], displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadFileAttachmentMethod: ['uploadFiles', 'both'], }, }, default: 'assistants', description: 'Select purpose for uploaded files', hint: '업로드할 파일의 목적 선택', }, { displayName: 'Enable File Attachments', name: 'threadFileIdsEnabled', type: 'boolean', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadFileAttachmentMethod: ['existingFiles', 'both'], }, }, default: true, description: 'Whether to attach existing uploaded files', hint: '기존 업로드된 파일을 첨부할지 여부', }, { displayName: 'File IDs', name: 'threadFileIds', type: 'multiOptions', typeOptions: { loadOptionsMethod: 'getFiles', }, displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadFileAttachmentMethod: ['existingFiles', 'both'], threadFileIdsEnabled: [true], }, }, default: [], description: 'File IDs to attach to the thread', hint: '스레드에 첨부할 파일 ID', }, { displayName: 'Wait for Completion', name: 'threadWaitForCompletion', type: 'boolean', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], }, }, default: true, description: 'Whether to wait for the run to complete before returning', hint: '실행 완료를 기다릴지 여부', }, { displayName: 'Maximum Poll Time (Seconds)', name: 'threadMaxPollTime', type: 'number', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], threadWaitForCompletion: [true], }, }, default: 120, description: 'Maximum time in seconds to wait for the run to complete', hint: '실행 완료를 대기하는 최대 시간(초)', }, { displayName: 'Instructions', name: 'threadInstructions', type: 'string', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], }, }, default: '', description: 'Override the default system instructions of the assistant', hint: '어시스턴트의 기본 시스템 지시사항을 재정의', required: false, }, { displayName: 'Simplify Output', name: 'threadSimplifyOutput', type: 'boolean', displayOptions: { show: { resource: ['thread'], operation: ['createAndRunThread'], }, }, default: true, description: 'Whether to return simplified response format', hint: '간단한 응답 형식으로 반환할지 여부', }, { displayName: 'Prompt', name: 'reportPrompt', type: 'string', typeOptions: { alwaysOpenEditWindow: true, rows: 4, }, displayOptions: { show: { resource: ['report'], operation: ['generateHtmlReport'], }, }, default: 'A4용지 1장 짜리 분량으로 모던하고 깔끔한 UI 라이브러리를 사용한 디자인으로 다음 데이터를 분석하고 시각화하는 HTML 보고서를 작성해주세요.', description: 'AI에게 보낼 보고서 생성 지시 프롬프트', hint: 'AI에게 보낼 보고서 생성 지시 프롬프트', required: true, }, { displayName: 'Input Text', name: 'reportInputText', type: 'string', typeOptions: { alwaysOpenEditWindow: true, rows: 5, }, displayOptions: { show: { resource: ['report'], operation: ['generateHtmlReport'], }, }, default: '', description: '분석할 텍스트 데이터', hint: '보고서로 변환할 텍스트 데이터를 입력하세요', required: true, }, { displayName: 'OpenAI Model', name: 'reportModel', type: 'options', typeOptions: { loadOptionsMethod: 'getCompletionModels', }, displayOptions: { show: { resource: ['report'], operation: ['generateHtmlReport'], }, }, default: 'gpt-4.1', description: '보고서 생성에 사용할 OpenAI 모델', hint: '보고서 생성에 사용할 OpenAI 모델', required: true, }, { displayName: 'Include Default Libraries', name: 'includeDefaultLibraries', type: 'boolean', displayOptions: { show: { resource: ['report'], operation: ['generateHtmlReport'], }, }, default: true, description: '부트스트랩, 차트JS 등 기본 UI 라이브러리를 포함합니다', hint: '부트스트랩, 차트JS 등 기본 UI 라이브러리를 포함합니다', }, { displayName: 'Advanced Settings', name: 'advancedSettings', type: 'boolean', displayOptions: { show: { resource: ['report'], operation: ['generateHtmlReport'], }, }, default: false, description: '생성 매개변수를 세부 조정합니다', hint: '생성 매개변수를 세부 조정합니다', },