@yk1028-test/ai-chat-supporter
Version:
AI Chat Supporter - TypeScript library for intelligent chat processing with LangChain integration
229 lines • 8.31 kB
JavaScript
;
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