UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

486 lines (424 loc) 11.9 kB
/** * @fileoverview Unified API wrapper for the RAG chatbot system * @module core/api/ChatbotAPI */ import type { ChatbotConfig, Document, Conversation, ConversationMessage, LLMConfig, VectorStoreConfig, StorageConfig, ChatbotError, } from "../contexts/ChatbotContext"; import type { ApiResponse, InitializationOptions, SearchOptions, FileUploadConstraints, } from "../../types/api"; import { createChatbotError } from "../../utils"; /** * Extended configuration interface for API initialization */ export interface ChatbotAPIConfig extends Partial<ChatbotConfig> { vectorStore?: VectorStoreConfig; llm?: LLMConfig; storage?: StorageConfig; } /** * Unified API class for the RAG chatbot system * Provides a clean, consistent interface for all chatbot operations */ export class ChatbotAPI { private initialized = false; private config: ChatbotAPIConfig | null = null; private errorHandlers: Array<(error: ChatbotError) => void> = []; /** * Initialize the chatbot system */ async initialize( config: ChatbotAPIConfig, options?: InitializationOptions ): Promise<ApiResponse<void>> { try { this.validateConfig(config); this.config = config; // Initialize components based on options const results = await Promise.allSettled([ !options?.skipVectorStore ? this.initializeVectorStore() : Promise.resolve(), !options?.skipLLM ? this.initializeLLM() : Promise.resolve(), !options?.skipStorage ? this.initializeStorage() : Promise.resolve(), ]); // Check for failures const failures = results.filter((result) => result.status === "rejected"); if (failures.length > 0 && !options?.retryOnFailure) { throw new Error( `Initialization failed: ${failures.length} components failed` ); } this.initialized = true; return { success: true, data: undefined, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "INITIALIZATION_FAILED", "Failed to initialize chatbot system", { originalError: error, config } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Reset the chatbot system */ async reset(): Promise<ApiResponse<void>> { try { // Reset all components await Promise.allSettled([ this.resetVectorStore(), this.resetLLM(), this.resetStorage(), ]); this.initialized = false; this.config = null; return { success: true, data: undefined, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "RESET_FAILED", "Failed to reset chatbot system", { originalError: error } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Send a message and get response */ async sendMessage( content: string, conversationId: string, options?: { useRAG?: boolean; context?: any } ): Promise<ApiResponse<ConversationMessage>> { try { this.ensureInitialized(); const message: ConversationMessage = { id: this.generateId("msg"), role: "user", content, timestamp: new Date(), }; // Process message through the system const response = options?.useRAG ? await this.processRAGMessage(message, conversationId) : await this.processDirectMessage(message, conversationId); return { success: true, data: response, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "MESSAGE_PROCESSING_FAILED", "Failed to process message", { originalError: error, content, conversationId } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Upload documents to the knowledge base */ async uploadDocuments( files: File[], constraints?: FileUploadConstraints, onProgress?: (progress: number) => void ): Promise<ApiResponse<Document[]>> { try { this.ensureInitialized(); // Validate files this.validateFiles(files, constraints); const documents: Document[] = []; for (let i = 0; i < files.length; i++) { const file = files[i]; onProgress?.((i / files.length) * 100); const document = await this.processFileUpload(file); documents.push(document); } onProgress?.(100); return { success: true, data: documents, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "DOCUMENT_UPLOAD_FAILED", "Failed to upload documents", { originalError: error, fileCount: files.length } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Search documents in the knowledge base */ async searchDocuments( query: string, options?: SearchOptions ): Promise<ApiResponse<Document[]>> { try { this.ensureInitialized(); const startTime = Date.now(); const results = await this.performSearch(query, options); const searchTime = Date.now() - startTime; return { success: true, data: results, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "SEARCH_FAILED", "Failed to search documents", { originalError: error, query, options } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Get system health status */ async getHealthStatus(): Promise<ApiResponse<any>> { try { const health = await this.checkSystemHealth(); return { success: true, data: health, timestamp: new Date().toISOString(), }; } catch (error) { const chatbotError = this.createError( "HEALTH_CHECK_FAILED", "Failed to check system health", { originalError: error } ); this.handleError(chatbotError); return { success: false, error: chatbotError.message, details: chatbotError.details, timestamp: new Date().toISOString(), }; } } /** * Add error handler */ onError(handler: (error: ChatbotError) => void): () => void { this.errorHandlers.push(handler); // Return unsubscribe function return () => { const index = this.errorHandlers.indexOf(handler); if (index > -1) { this.errorHandlers.splice(index, 1); } }; } /** * Get current configuration */ getConfig(): ChatbotAPIConfig | null { return this.config; } /** * Check if system is initialized */ isInitialized(): boolean { return this.initialized; } // Private helper methods private ensureInitialized(): void { if (!this.initialized) { throw new Error( "Chatbot system is not initialized. Call initialize() first." ); } } private validateConfig(config: ChatbotAPIConfig): void { if (!config) { throw new Error("Configuration is required"); } // Add more specific validation logic here if (!config.llm) { throw new Error("LLM configuration is required"); } } private validateFiles( files: File[], constraints?: FileUploadConstraints ): void { if (!files || files.length === 0) { throw new Error("No files provided"); } if (constraints) { for (const file of files) { if (file.size > constraints.maxSize) { throw new Error( `File ${file.name} exceeds maximum size of ${constraints.maxSize} bytes` ); } if ( constraints.allowedTypes && !constraints.allowedTypes.includes(file.type) ) { throw new Error(`File type ${file.type} is not allowed`); } } } } private createError( code: string, message: string, details?: any ): ChatbotError { return createChatbotError(code, message, details); } private handleError(error: ChatbotError): void { this.errorHandlers.forEach((handler) => { try { handler(error); } catch (handlerError) { console.error("Error in error handler:", handlerError); } }); } private generateId(prefix: string): string { return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } // Placeholder methods for implementation private async initializeVectorStore(): Promise<void> { // Implementation will be connected to existing vector store service console.log("Initializing vector store..."); } private async initializeLLM(): Promise<void> { // Implementation will be connected to existing LLM service console.log("Initializing LLM..."); } private async initializeStorage(): Promise<void> { // Implementation will be connected to existing storage service console.log("Initializing storage..."); } private async resetVectorStore(): Promise<void> { console.log("Resetting vector store..."); } private async resetLLM(): Promise<void> { console.log("Resetting LLM..."); } private async resetStorage(): Promise<void> { console.log("Resetting storage..."); } private async processRAGMessage( message: ConversationMessage, conversationId: string ): Promise<ConversationMessage> { // Implementation will use existing RAG chain service return { id: this.generateId("msg"), role: "assistant", content: "RAG response placeholder", timestamp: new Date(), }; } private async processDirectMessage( message: ConversationMessage, conversationId: string ): Promise<ConversationMessage> { // Implementation will use direct LLM service return { id: this.generateId("msg"), role: "assistant", content: "Direct response placeholder", timestamp: new Date(), }; } private async processFileUpload(file: File): Promise<Document> { // Implementation will use existing storage service return { id: this.generateId("doc"), title: file.name, content: "", metadata: { source: file.name, uploadedAt: new Date(), size: file.size, type: file.type, description: `Uploaded file: ${file.name}`, }, status: "processing", }; } private async performSearch( query: string, options?: SearchOptions ): Promise<Document[]> { // Implementation will use existing vector store search return []; } private async checkSystemHealth(): Promise<any> { // Implementation will check all components return { overall: true, components: { vectorStore: true, llm: true, storage: true, }, }; } } /** * Default singleton instance */ export const chatbotAPI = new ChatbotAPI(); export default ChatbotAPI;