> ## Documentation Index
> Fetch the complete documentation index at: https://ai-kb.automationanywhere.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat SDK

> EKB Chat SDK를 사용하여 애플리케이션에 대화형 AI 인터페이스를 통합합니다.

ChatSDK는 EKB 콘텐츠 크리에이터 SDK의 핵심 컴포넌트로, 대화형 AI 애플리케이션을 쉽게 구축할 수 있게 합니다. 포괄적인 채팅 관리, 메시지 처리, 스트리밍 응답 및 지식 기반 통합을 제공합니다. 이 기사에서는 SDK를 설치하고 빠르게 시작하는 방법을 알아봅니다. 다양한 구성 옵션을 탐색하고, 인증 방법을 알아보며, 이 SDK에서 사용할 수 있는 핵심 메서드를 배웁니다.

## 설치

```bash theme={null}
npm install @odin-ai-staging/sdk
```

## 빠른 시작

```typescript theme={null}
import { ChatSDK } from '@odin-ai-staging/sdk';

// SDK 초기화
const chatSDK = new ChatSDK({
  baseUrl: 'https://your-api-endpoint.com/',
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
  apiSecret: 'your-api-secret'
});

// 채팅을 만들고 메시지를 보냄
async function quickExample() {
  // 새 채팅 만들기
  const chat = await chatSDK.createChat('My First Chat');
  
  // 메시지 보내기
  const response = await chatSDK.sendMessage('Hello, how can you help me?', {
    chatId: chat.chat_id
  });
  
  console.log('AI Response:', response.message);
}
```

## 구성

### ChatSDKConfig 인터페이스

```typescript theme={null}
interface ChatSDKConfig {
  baseUrl: string;          // API 엔드포인트 URL
  projectId: string;        // 프로젝트 식별자
  apiKey?: string;          // 인증용 API 키
  apiSecret?: string;       // 인증용 API 시크릿
  accessToken?: string;     // 웹 앱 사용을 위한 액세스 토큰
}
```

### 구성 옵션

* **baseUrl**: API 엔드포인트의 기본 URL
* **projectId**: 고유한 프로젝트 식별자
* **apiKey** & **apiSecret**: 서버 측 인증용
* **accessToken**: 클라이언트 측 인증용 (웹 앱)

## 인증

ChatSDK는 두 가지 인증 방법을 지원합니다:

### API 키 인증 (서버 측)

```typescript theme={null}
const chatSDK = new ChatSDK({
  baseUrl: 'https://api.example.com/',
  projectId: 'proj_123',
  apiKey: 'your-api-key',
  apiSecret: 'your-api-secret'
});
```

### 액세스 토큰 인증 (클라이언트 측)

```typescript theme={null}
const chatSDK = new ChatSDK({
  baseUrl: 'https://api.example.com/',
  projectId: 'proj_123',
  accessToken: 'your-access-token'
});
```

## 핵심 메서드

### 채팅 관리

#### `createChat(name?, documentKeys?)`

새 채팅 대화를 만듭니다.

```typescript theme={null}
async createChat(
  name?: string,           // 선택적 채팅 이름 (기본값: "제목 없음")
  documentKeys?: string[]  // 선택적 지식 기반 컨텍스트를 위한 문서 키
): Promise<CreateChatResponse>
```

**예시:**

```typescript theme={null}
// 기본 채팅 만들기
const chat = await chatSDK.createChat('고객 지원 채팅');

// 지식 기반 컨텍스트가 있는 채팅 만들기
const chatWithDocs = await chatSDK.createChat(
  '제품 문서화 채팅',
  ['doc_key_1', 'doc_key_2']
);
```

#### `listChats(cursor?, limit?)`

프로젝트의 페이지네이션된 채팅 목록을 가져옵니다.

```typescript theme={null}
async listChats(
  cursor?: number,  // 선택적 페이지네이션 커서
  limit?: number    // 반환할 채팅 수 (기본값: 30, 최대: 100)
): Promise<ListChatsResponse>
```

**예시:**

```typescript theme={null}
// 처음 10개 채팅 가져오기
const chats = await chatSDK.listChats(undefined, 10);

// 커서를 사용하여 다음 페이지 가져오기
if (chats.next_cursor) {
  const nextPage = await chatSDK.listChats(chats.next_cursor, 10);
}
```

#### `getChatHistory(chatId)`

전체 메시지 기록이 포함된 채팅을 가져옵니다.

```typescript theme={null}
async getChatHistory(chatId: string): Promise<ChatHistoryResponse>
```

**예시:**

```typescript theme={null}
const chatHistory = await chatSDK.getChatHistory('chat_123');
console.log('Messages:', chatHistory.messages);
```

#### `deleteChat(chatId)`

채팅과 모든 메시지를 영구적으로 삭제합니다.

```typescript theme={null}
async deleteChat(chatId: string): Promise<void>
```

**예시:**

```typescript theme={null}
await chatSDK.deleteChat('chat_123');
```

#### `updateChatName(chatId, newName)`

기존 채팅의 표시 이름을 업데이트합니다.

```typescript theme={null}
async updateChatName(chatId: string, newName: string): Promise<void>
```

**예시:**

```typescript theme={null}
await chatSDK.updateChatName('chat_123', '업데이트된 채팅 이름');
```

### 메시지 처리

#### `sendMessage(message, options?)`

메시지를 보내고 AI 응답을 받습니다.

```typescript theme={null}
async sendMessage(
  message: string,
  options?: SendMessageOptions
): Promise<SendMessageResponse>
```

**SendMessageOptions:**

```typescript theme={null}
interface SendMessageOptions {
  chatId?: string;          // 대상 채팅 ID
  agentType?: AgentType;    // 사용할 AI 에이전트 유형
  agentId?: string;         // 특정 에이전트 ID
  documentKeys?: string[];  // 지식 기반 문서
  images?: File[];          // 이미지 첨부
  metadata?: Record<string, any>;  // 사용자 지정 메타데이터
  modelName?: ModelName;    // 사용할 AI 모델
  useKnowledgebase?: boolean;      // 지식 기반 활성화
  isTest?: boolean;         // 테스트 모드 플래그
  googleSearch?: boolean;   // 웹 검색 활성화
  formatInstructions?: string;     // 응답 형식 안내
  ignoreChatHistory?: boolean;     // 대화 기록 무시
  exampleJson?: string;     // 구조화된 응답을 위한 예시 JSON
  skipStream?: boolean;     // 스트리밍 비활성화
}
```

**예시:**

```typescript theme={null}
// 기본 메시지
const response = await chatSDK.sendMessage('인공지능이란 무엇인가요?', {
  chatId: 'chat_123'
});

// 옵션이 포함된 고급 메시지
const advancedResponse = await chatSDK.sendMessage(
  '이 데이터를 분석하고 인사이트를 제공하세요',
  {
    chatId: 'chat_123',
    modelName: 'gpt-4o',
    useKnowledgebase: true,
    googleSearch: true,
    formatInstructions: '글머리 기호로 응답을 제공하세요'
  }
);
```

#### `sendFeedback(messageId, chatId, feedback)`

AI 응답에 대한 피드백을 제공합니다.

```typescript theme={null}
async sendFeedback(
  messageId: string,
  chatId: string,
  feedback: boolean  // true = 좋아요, false = 싫어요
): Promise<void>
```

**예시:**

```typescript theme={null}
// 긍정적 피드백
await chatSDK.sendFeedback('msg_123', 'chat_123', true);

// 부정적 피드백
await chatSDK.sendFeedback('msg_123', 'chat_123', false);
```

## 스트리밍 지원

### `sendMessageStream(message, options)`

실시간 스트리밍 응답이 포함된 메시지를 보냅니다.

```typescript theme={null}
async sendMessageStream(
  message: string,
  options: SendMessageOptions & StreamCallbacks
): Promise<void>
```

**StreamCallbacks:**

```typescript theme={null}
interface StreamCallbacks {
  onChunk?: (chunk: string) => void;           // 텍스트 청크
  onMessageObject?: (messageObject: any) => void;  // 구조화된 데이터
  onComplete?: (message: Message) => void;     // 최종 메시지
  onError?: (error: Error) => void;           // 오류 처리기
  onChatNameUpdate?: (chatName: string) => void;   // 채팅 이름 변경
  onDocumentChunk?: (chunk: string) => void;  // 문서 처리 업데이트
  onMessageEnd?: () => void;                  // 스트림 완료
}
```

**예시:**

```typescript theme={null}
await chatSDK.sendMessageStream(
  '머신 러닝에 대해 알려주세요',
  {
    chatId: 'chat_123',
    onChunk: (chunk) => {
      // 스트리밍되는 텍스트를 표시
      console.log('Chunk:', chunk);
      updateUI(chunk);
    },
    onComplete: (message) => {
      console.log('Complete message:', message);
      finalizeUI(message);
    },
    onError: (error) => {
      console.error('Stream error:', error);
      showError(error.message);
    }
  }
);
```

## 오류 처리

SDK는 API 관련 실패에 대해 `APIError` 객체를 발생시킵니다:

```typescript theme={null}
interface APIError {
  message: string;  // 오류 설명
  status: number;   // HTTP 상태 코드
  detail?: string;  // 추가 오류 세부 정보
}
```

**예시:**

```typescript theme={null}
try {
  const response = await chatSDK.sendMessage('Hello');
} catch (error) {
  if (error instanceof APIError) {
    console.error(`API Error ${error.status}: ${error.message}`);
    if (error.detail) {
      console.error('Details:', error.detail);
    }
  } else {
    console.error('Unexpected error:', error);
  }
}
```

## 예시

### 기본 채팅 애플리케이션

이 예시에서는 EKB SDK를 사용하여 단순한 비스트리밍 메시지 교환으로 기본 채팅 애플리케이션을 구축하는 방법을 알아봅니다. 환경 변수에서 API 자격 증명을 가져와 ChatSDK를 초기화하는 `SimpleChatApp` 클래스를 만드는 것으로 시작합니다. 클래스는 `currentChatId`로 현재 채팅 세션을 추적하고 세 가지 주요 메서드를 제공합니다: `startNewChat()`은 사용자 지정 이름으로 새 채팅 대화를 만들고, `sendMessage()`는 AI에 메시지를 보내고 완전한 응답을 반환하며(채팅이 없으면 자동으로 만듦), `getChatList()`는 기존 채팅 대화를 가져옵니다.

```typescript theme={null}
import { ChatSDK } from '@odin-ai-staging/sdk';

class SimpleChatApp {
  private chatSDK: ChatSDK;
  private currentChatId?: string;

  constructor() {
    this.chatSDK = new ChatSDK({
      baseUrl: process.env.API_BASE_URL,
      projectId: process.env.PROJECT_ID,
      apiKey: process.env.API_KEY,
      apiSecret: process.env.API_SECRET
    });
  }

  async startNewChat(name: string = '새 채팅') {
    try {
      const chat = await this.chatSDK.createChat(name);
      this.currentChatId = chat.chat_id;
      console.log(`채팅 만들기: ${chat.name} (${chat.chat_id})`);
      return chat;
    } catch (error) {
      console.error('채팅 만들기 실패:', error);
      throw error;
    }
  }

  async sendMessage(message: string) {
    if (!this.currentChatId) {
      await this.startNewChat();
    }

    try {
      const response = await this.chatSDK.sendMessage(message, {
        chatId: this.currentChatId,
        modelName: 'gpt-4o-mini'
      });

      console.log('사용자:', message);
      console.log('AI:', response.message);
      
      return response;
    } catch (error) {
      console.error('메시지 보내기 실패:', error);
      throw error;
    }
  }

  async getChatList() {
    try {
      const chats = await this.chatSDK.listChats();
      return chats.chats;
    } catch (error) {
      console.error('채팅 목록 가져오기 실패:', error);
      throw error;
    }
  }
}

// 사용
const app = new SimpleChatApp();
await app.sendMessage('안녕하세요, 어떻게 도와드릴까요?');
```

### 실시간 업데이트가 포함된 스트리밍 채팅

이 예시에서는 EKB API에 연결하고 AI 응답을 실시간으로 표시하는 스트리밍 채팅 인터페이스를 구축하는 방법을 알아봅니다. API 자격 증명으로 ChatSDK를 초기화하고 메시지가 표시될 HTML 요소에 대한 참조를 포함하는 `StreamingChat` 클래스를 만드는 것으로 시작합니다.

```typescript theme={null}
import { ChatSDK, StreamCallbacks } from '@odin-ai-staging/sdk';

class StreamingChat {
  private chatSDK: ChatSDK;
  private messageElement: HTMLElement;

  constructor(messageElement: HTMLElement) {
    this.messageElement = messageElement;
    this.chatSDK = new ChatSDK({
      baseUrl: 'https://your-api.com/',
      projectId: 'your-project-id',
      accessToken: 'your-access-token'
    });
  }

  async sendStreamingMessage(message: string, chatId: string) {
    this.messageElement.innerHTML = '';

    const callbacks: StreamCallbacks = {
      onChunk: (chunk: string) => {
        this.messageElement.innerHTML += chunk;
        this.messageElement.scrollIntoView();
      },
      onMessageObject: (messageObj: any) => {
        if (messageObj.image_urls) {
          this.displayImages(messageObj.image_urls);
        }
      },
      onComplete: (message: any) => {
        console.log('메시지 완료:', message);
        this.finalizeMessage(message);
      },
      onError: (error: Error) => {
        console.error('스트리밍 오류:', error);
        this.messageElement.innerHTML = `오류: ${error.message}`;
      },
      onChatNameUpdate: (chatName: string) => {
        document.title = chatName;
      }
    };

    try {
      await this.chatSDK.sendMessageStream(message, {
        chatId,
        modelName: 'gpt-4o',
        useKnowledgebase: true,
        ...callbacks
      });
    } catch (error) {
      console.error('스트리밍 메시지 보내기 실패:', error);
    }
  }

  private displayImages(imageUrls: string[]) {
    imageUrls.forEach(url => {
      const img = document.createElement('img');
      img.src = url;
      img.style.maxWidth = '100%';
      this.messageElement.appendChild(img);
    });
  }

  private finalizeMessage(message: any) {
    const feedbackDiv = document.createElement('div');
    feedbackDiv.innerHTML = `
      <button onclick="this.provideFeedback('${message.id}', true)">👍</button>
      <button onclick="this.provideFeedback('${message.id}', false)">👎</button>
    `;
    this.messageElement.appendChild(feedbackDiv);
  }

  async provideFeedback(messageId: string, isPositive: boolean) {
    try {
      await this.chatSDK.sendFeedback(messageId, 'chat_id', isPositive);
      console.log('피드백이 성공적으로 전송되었습니다');
    } catch (error) {
      console.error('피드백 보내기 실패:', error);
    }
  }
}
```

### 지식 기반 통합

이 예시에서는 지식 기반에 업로드된 특정 문서를 기반으로 질문에 답변할 수 있는 지식 기반 기반 채팅 애플리케이션을 구축하는 방법을 알아봅니다.

```typescript theme={null}
import { ChatSDK } from '@odin-ai-staging/sdk';

class KnowledgeBasedChat {
  private chatSDK: ChatSDK;

  constructor() {
    this.chatSDK = new ChatSDK({
      baseUrl: process.env.API_BASE_URL,
      projectId: process.env.PROJECT_ID,
      apiKey: process.env.API_KEY,
      apiSecret: process.env.API_SECRET
    });
  }

  async createDocumentChat(documentKeys: string[], chatName?: string) {
    try {
      const chat = await this.chatSDK.createChat(
        chatName || '문서 Q&A',
        documentKeys
      );
      
      console.log(`${documentKeys.length}개 문서로 문서 채팅 만들기`);
      return chat;
    } catch (error) {
      console.error('문서 채팅 만들기 실패:', error);
      throw error;
    }
  }

  async askDocumentQuestion(question: string, chatId: string, documentKeys?: string[]) {
    try {
      const response = await this.chatSDK.sendMessage(question, {
        chatId,
        documentKeys,
        useKnowledgebase: true,
        agentType: 'document_agent',
        formatInstructions: '출처에 대한 인용을 제공하세요'
      });

      if (response.message.sources) {
        console.log('출처:', response.message.sources);
      }

      return response;
    } catch (error) {
      console.error('문서 질문하기 실패:', error);
      throw error;
    }
  }
}

// 사용
const kbChat = new KnowledgeBasedChat();
const chat = await kbChat.createDocumentChat(['doc_1', 'doc_2'], '제품 FAQ');
const answer = await kbChat.askDocumentQuestion(
  '제품의 주요 기능은 무엇인가요?',
  chat.chat_id
);
```

## 모범 사례

### 오류 처리

모든 SDK 메서드에 대해 적절한 오류 처리를 항상 구현합니다:

```typescript theme={null}
try {
  const response = await chatSDK.sendMessage(message, options);
  // 성공 처리
} catch (error) {
  if (error instanceof APIError) {
    console.error(`API 오류: ${error.message}`);
  } else {
    console.error('예상치 못한 오류:', error);
  }
}
```

### 더 나은 UX를 위한 스트리밍

더 긴 응답에 대해 실시간 피드백을 제공하기 위해 스트리밍을 사용합니다:

```typescript theme={null}
await chatSDK.sendMessageStream(longQuery, {
  onChunk: (chunk) => updateUI(chunk),
  onComplete: (message) => finalizeUI(message)
});
```

### API 호출 최적화

* 각 메시지에 대해 새 채팅을 만드는 대신 채팅 ID를 재사용합니다
* 채팅 목록에 페이지네이션을 사용합니다
* 자주 접근하는 데이터에 캐싱을 구현합니다

```typescript theme={null}
class OptimizedChatManager {
  private chatCache = new Map<string, any>();
  private currentChatId?: string;

  async getOrCreateChat(name?: string) {
    if (this.currentChatId) {
      return this.currentChatId;
    }
    const chat = await this.chatSDK.createChat(name);
    this.currentChatId = chat.chat_id;
    return this.currentChatId;
  }

  async getCachedChatHistory(chatId: string) {
    if (this.chatCache.has(chatId)) {
      return this.chatCache.get(chatId);
    }
    const history = await this.chatSDK.getChatHistory(chatId);
    this.chatCache.set(chatId, history);
    return history;
  }
}
```

### 구성 관리

구성을 안전하게 저장하고 환경 변수를 사용합니다:

```typescript theme={null}
// 좋음: 환경 변수 사용
const chatSDK = new ChatSDK({
  baseUrl: process.env.ODIN_API_BASE_URL,
  projectId: process.env.ODIN_PROJECT_ID,
  apiKey: process.env.ODIN_API_KEY,
  apiSecret: process.env.ODIN_API_SECRET
});
```

### 메모리 관리

리소스를 정리하고 메모리 누수를 방지합니다:

```typescript theme={null}
class ChatApplication {
  private activeStreams = new Set<AbortController>();

  async sendStreamingMessage(message: string, options: any) {
    const controller = new AbortController();
    this.activeStreams.add(controller);
    try {
      await this.chatSDK.sendMessageStream(message, {
        ...options,
        signal: controller.signal
      });
    } finally {
      this.activeStreams.delete(controller);
    }
  }

  cleanup() {
    this.activeStreams.forEach(controller => controller.abort());
    this.activeStreams.clear();
  }
}
```
