UNPKG

@yk1028-test/ai-chat-supporter

Version:

AI Chat Supporter - TypeScript library for intelligent chat processing with LangChain integration

229 lines 8.31 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.RAGManager = exports.TextDocumentProcessor = void 0; const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); // 텍스트 파일 처리기 class TextDocumentProcessor { constructor() { this.supportedExtensions = ['.txt', '.md', '.text']; } async process(filePath) { try { const content = await fs.readFile(filePath, 'utf-8'); const stats = await fs.stat(filePath); const fileName = path.basename(filePath, path.extname(filePath)); return { id: this.generateId(filePath), title: fileName, content: content.trim(), filePath, metadata: { fileSize: stats.size, extension: path.extname(filePath), }, lastModified: stats.mtime, }; } catch (error) { throw new Error(`텍스트 파일 처리 중 오류 발생: ${error instanceof Error ? error.message : 'Unknown error'}`); } } generateId(filePath) { // 파일 경로를 기반으로 간단한 ID 생성 return Buffer.from(filePath).toString('base64').replace(/[^a-zA-Z0-9]/g, '').substring(0, 16); } } exports.TextDocumentProcessor = TextDocumentProcessor; // RAG 관리자 class RAGManager { constructor(config = {}) { this.documents = new Map(); this.processors = new Map(); this.config = { maxDocuments: 10, maxContextLength: 4000, similarityThreshold: 0.5, chunkSize: 1000, chunkOverlap: 200, ...config, }; // 기본 처리기 등록 this.registerProcessor(new TextDocumentProcessor()); } // 문서 처리기 등록 registerProcessor(processor) { processor.supportedExtensions.forEach(ext => { this.processors.set(ext, processor); }); } // 문서 추가 async addDocument(filePath) { const extension = path.extname(filePath).toLowerCase(); const processor = this.processors.get(extension); if (!processor) { throw new Error(`지원하지 않는 파일 형식: ${extension}`); } try { const document = await processor.process(filePath); this.documents.set(document.id, document); return document; } catch (error) { throw new Error(`문서 추가 중 오류 발생: ${error instanceof Error ? error.message : 'Unknown error'}`); } } // 여러 문서 일괄 추가 async addDocuments(filePaths) { const results = []; const errors = []; for (const filePath of filePaths) { try { const document = await this.addDocument(filePath); results.push(document); } catch (error) { errors.push(`${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } if (errors.length > 0) { console.warn('일부 문서 추가 실패:', errors); } return results; } // 문서 삭제 removeDocument(documentId) { return this.documents.delete(documentId); } // 문서 조회 getDocument(documentId) { return this.documents.get(documentId); } // 모든 문서 목록 listDocuments() { return Array.from(this.documents.values()); } // 키워드 기반 문서 검색 (간단한 구현) searchDocuments(query) { const queryLower = query.toLowerCase(); const relevantDocs = []; for (const document of this.documents.values()) { const score = this.calculateSimpleScore(document, queryLower); if (score > 0) { relevantDocs.push({ document, score }); } } // 점수순으로 정렬하고 상위 문서들만 반환 return relevantDocs .sort((a, b) => b.score - a.score) .slice(0, this.config.maxDocuments) .map(item => item.document); } // RAG 컨텍스트 구축 buildContext(query) { const relevantDocs = this.searchDocuments(query); const contextChunks = []; let currentLength = 0; for (const doc of relevantDocs) { const chunks = this.chunkDocument(doc); for (const chunk of chunks) { if (currentLength + chunk.length > this.config.maxContextLength) { break; } contextChunks.push(`[${doc.title}]\n${chunk}`); currentLength += chunk.length; } if (currentLength >= this.config.maxContextLength) { break; } } return contextChunks; } // 문서를 청크로 분할 chunkDocument(document) { const { chunkSize, chunkOverlap } = this.config; const content = document.content; const chunks = []; if (content.length <= chunkSize) { return [content]; } let start = 0; while (start < content.length) { const end = Math.min(start + chunkSize, content.length); chunks.push(content.substring(start, end)); start += chunkSize - chunkOverlap; } return chunks; } // 간단한 점수 계산 (TF-IDF나 임베딩 대신 사용) calculateSimpleScore(document, query) { const contentLower = (document.title + ' ' + document.content).toLowerCase(); const queryWords = query.split(/\s+/).filter(word => word.length > 2); let score = 0; for (const word of queryWords) { const matches = (contentLower.match(new RegExp(word, 'g')) || []).length; score += matches; } // 제목에서 찾은 경우 가중치 부여 const titleLower = document.title.toLowerCase(); for (const word of queryWords) { if (titleLower.includes(word)) { score += 5; } } return score; } // 설정 업데이트 updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; } // 지원하는 파일 형식 조회 getSupportedExtensions() { return Array.from(this.processors.keys()); } // 통계 정보 getStats() { const docs = this.listDocuments(); const totalContentLength = docs.reduce((sum, doc) => sum + doc.content.length, 0); return { documentCount: docs.length, totalContentLength, supportedExtensions: this.getSupportedExtensions(), }; } } exports.RAGManager = RAGManager; //# sourceMappingURL=RAGManager.js.map