@kangthink/q-engine
Version:
A question-answer generation engine that stimulates thinking
132 lines • 5.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseTransform = void 0;
const types_1 = require("../types");
const Node_1 = require("../models/Node");
const Edge_1 = require("../models/Edge");
class BaseTransform {
constructor(llmProvider, promptManager) {
// 각 Transform의 기본 타겟 타입 (하위 클래스에서 오버라이드 가능)
this.defaultTargetType = types_1.NodeType.QUESTION;
this.llmProvider = llmProvider;
this.promptManager = promptManager;
}
async transformMultiple(context) {
const { sourceNode, options } = context;
const count = options?.count || 3;
const targetNodeType = options?.targetNodeType || this.defaultTargetType;
// Get or create prompt template
const promptTemplate = this.promptManager.getPrompt(this.mode) ||
this.promptManager.getDefaultPrompt(this.mode);
// Build prompt for multiple generation
const targetTypeKorean = targetNodeType === types_1.NodeType.QUESTION ? '질문' : '답변';
const prompt = this.buildMultiplePrompt(promptTemplate.template, {
content: sourceNode.content,
targetType: targetTypeKorean,
count: count,
...options
});
// Generate content using LLM
const generatedContent = await this.generateContent(prompt);
// Parse multiple results
const contents = this.parseMultipleResults(generatedContent);
// Create nodes and edges
const targetNodes = [];
const edges = [];
contents.forEach(content => {
const targetNode = targetNodeType === types_1.NodeType.QUESTION
? Node_1.NodeBuilder.createQuestion(content.trim())
: Node_1.NodeBuilder.createAnswer(content.trim());
const edge = new Edge_1.EdgeBuilder(sourceNode.id, targetNode.id, this.mode, {
transformedAt: new Date(),
sourceType: sourceNode.type,
targetType: targetNodeType,
});
targetNodes.push(targetNode);
edges.push(edge);
});
return {
targetNodes,
edges,
};
}
async generateContent(prompt) {
return await this.llmProvider.generateResponse(prompt);
}
createTransformResult(sourceNode, generatedContent, targetNodeType = types_1.NodeType.QUESTION) {
const targetNode = targetNodeType === types_1.NodeType.QUESTION
? Node_1.NodeBuilder.createQuestion(generatedContent)
: Node_1.NodeBuilder.createAnswer(generatedContent);
const edge = new Edge_1.EdgeBuilder(sourceNode.id, targetNode.id, this.mode, {
transformedAt: new Date(),
sourceType: sourceNode.type,
targetType: targetNodeType,
});
return {
targetNode,
edge,
};
}
buildPrompt(template, variables) {
let prompt = template;
Object.entries(variables).forEach(([key, value]) => {
const placeholder = `{{${key}}}`;
prompt = prompt.replace(new RegExp(placeholder, 'g'), String(value));
});
return prompt;
}
buildMultiplePrompt(template, variables) {
return this.buildPrompt(template, variables);
}
parseMultipleResults(content) {
// 번호가 매겨진 리스트 파싱 (1. 2. 3. 또는 1) 2) 3) 형식)
const numbered = content.match(/^\d+[.)]\s*(.+)$/gm);
if (numbered && numbered.length > 1) {
return numbered.map(line => line.replace(/^\d+[.)]\s*/, '').trim());
}
// 줄바꿈으로 구분된 경우 - 빈 줄과 구분자는 제외
const lines = content.split('\n')
.map(line => line.trim())
.filter(line => {
if (line.length === 0)
return false;
if (line.match(/^[\d\-\*\.•]\s*$/))
return false;
if (line.match(/^-+$/))
return false;
if (line.match(/^\*+$/))
return false;
return true;
});
// 각 줄이 유효한 질문/답변인지 확인
const validLines = lines.filter(line => {
// 너무 짧은 텍스트는 제외
if (line.length < 3)
return false;
// 단순 구분자는 제외
if (line.match(/^[\d\-\*\.•\s]+$/))
return false;
return true;
});
if (validLines.length > 1) {
return validLines;
}
// 단일 결과인 경우 - 여러 질문이 하나의 텍스트에 들어있을 수 있음
const singleContent = content.trim();
// 질문 패턴으로 분리 시도 (? 로 끝나는 문장들)
const questionPattern = /[^?]*\?/g;
const questions = singleContent.match(questionPattern);
if (questions && questions.length > 1) {
return questions.map(q => q.trim()).filter(q => q.length > 3);
}
// 문장 단위로 분리 시도 (. 또는 ? 또는 ! 로 끝나는 문장들)
const sentencePattern = /[^.!?]*[.!?]/g;
const sentences = singleContent.match(sentencePattern);
if (sentences && sentences.length > 1) {
return sentences.map(s => s.trim()).filter(s => s.length > 3);
}
return [singleContent];
}
}
exports.BaseTransform = BaseTransform;
//# sourceMappingURL=BaseTransform.js.map