Files
김보곤 d86b5851d0 chore: 프로젝트 설정 및 문서 파일 추가
- .agent/, .claude/, .vscode/ 설정 파일
- design/ 디자인 리소스
- reports/, research/ 분석 문서
- testcase/ 테스트 케이스 문서
- db_sync_chandj.bat, sam.code-workspace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:51:43 +09:00

483 lines
13 KiB
JavaScript

/**
* 통합 실행 스크립트
* 'ppt' 또는 '실행' 명령어로 source/*.txt → PPTX 변환 실행
*/
const fs = require('fs').promises;
const path = require('path');
const readline = require('readline');
const { spawn } = require('child_process');
// 색상 출력을 위한 유틸리티
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
blue: '\x1b[34m',
yellow: '\x1b[33m',
red: '\x1b[31m',
cyan: '\x1b[36m'
};
class PPTGenerator {
constructor() {
this.sourceDir = 'source';
this.outputDir = 'pptx';
this.scriptPath = '.claude/skills/text-analyzer-skill/scripts/txt-to-pptx.js';
}
/**
* 메인 실행 함수
*/
async run() {
this.printHeader();
try {
// 1. 환경 체크
await this.checkEnvironment();
// 2. 텍스트 파일 찾기
const txtFiles = await this.findTxtFiles();
if (txtFiles.length === 0) {
this.printError('source 폴더에 txt 파일이 없습니다.');
await this.createSampleFile();
return;
}
// 3. 파일 선택
const selectedFile = await this.selectFile(txtFiles);
if (!selectedFile) {
this.printInfo('작업이 취소되었습니다.');
return;
}
// 4. PPTX 생성
await this.generatePPTX(selectedFile);
} catch (error) {
this.printError(`실행 중 오류 발생: ${error.message}`);
console.error(error.stack);
}
}
/**
* 헤더 출력
*/
printHeader() {
console.clear();
console.log(colors.cyan + colors.bright);
console.log('██████████████████████████████████████████');
console.log('█ TXT → PPTX 자동 변환 시스템 █');
console.log('█ Text to PowerPoint Converter █');
console.log('██████████████████████████████████████████');
console.log(colors.reset);
console.log();
}
/**
* 환경 체크
*/
async checkEnvironment() {
this.printInfo('🔍 환경 확인 중...');
// source 디렉토리 체크
try {
await fs.access(this.sourceDir);
} catch {
await fs.mkdir(this.sourceDir, { recursive: true });
this.printSuccess(`✅ source 디렉토리 생성됨`);
}
// pptx 출력 디렉토리 체크
try {
await fs.access(this.outputDir);
} catch {
await fs.mkdir(this.outputDir, { recursive: true });
this.printSuccess(`${this.outputDir} 디렉토리 생성됨`);
}
// 변환 스크립트 체크
try {
await fs.access(this.scriptPath);
this.printSuccess('✅ 변환 스크립트 확인됨');
} catch {
this.printError(`❌ 변환 스크립트를 찾을 수 없습니다: ${this.scriptPath}`);
throw new Error('변환 스크립트가 없습니다.');
}
}
/**
* 텍스트 파일 검색
*/
async findTxtFiles() {
try {
const files = await fs.readdir(this.sourceDir);
const txtFiles = files.filter(file => file.endsWith('.txt'));
this.printInfo(`📁 ${this.sourceDir} 디렉토리에서 ${txtFiles.length}개의 txt 파일을 찾았습니다.`);
return txtFiles.map(file => ({
name: file,
path: path.join(this.sourceDir, file),
size: 0 // 크기는 나중에 필요시 추가
}));
} catch (error) {
this.printError(`디렉토리 읽기 실패: ${error.message}`);
return [];
}
}
/**
* 파일 선택 인터페이스
*/
async selectFile(files) {
if (files.length === 1) {
this.printInfo(`📄 파일 자동 선택: ${files[0].name}`);
return files[0];
}
console.log(colors.yellow + '\n📋 변환할 파일을 선택하세요:' + colors.reset);
files.forEach((file, index) => {
console.log(` ${index + 1}. ${file.name}`);
});
console.log(` 0. 취소`);
console.log();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve) => {
rl.question('선택 (번호 입력): ', (answer) => {
rl.close();
const choice = parseInt(answer);
if (choice === 0) {
resolve(null);
} else if (choice >= 1 && choice <= files.length) {
resolve(files[choice - 1]);
} else {
this.printError('잘못된 선택입니다.');
resolve(null);
}
});
});
}
/**
* PPTX 생성 실행
*/
async generatePPTX(file) {
this.printInfo(`🚀 PPTX 생성 시작: ${file.name}`);
const outputFileName = file.name.replace('.txt', '_presentation.pptx');
const outputPath = path.join(this.outputDir, outputFileName);
return new Promise((resolve, reject) => {
const child = spawn('node', [
this.scriptPath,
`--input=${file.path}`,
`--output=${outputPath}`
], {
stdio: 'inherit'
});
child.on('close', (code) => {
if (code === 0) {
this.printSuccess(`🎉 변환 완료!`);
this.printInfo(`📊 생성된 파일: ${outputPath}`);
// 파일 크기 표시
fs.stat(outputPath)
.then(stats => {
const sizeKB = (stats.size / 1024).toFixed(1);
this.printInfo(`📏 파일 크기: ${sizeKB} KB`);
})
.catch(() => {});
resolve();
} else {
reject(new Error(`변환 프로세스가 코드 ${code}로 종료되었습니다.`));
}
});
child.on('error', (error) => {
reject(new Error(`변환 프로세스 실행 실패: ${error.message}`));
});
});
}
/**
* 샘플 파일 생성
*/
async createSampleFile() {
const samplePath = path.join(this.sourceDir, 'sample_project.txt');
try {
await fs.access(samplePath);
this.printInfo('샘플 파일이 이미 존재합니다: sample_project.txt');
return;
} catch {
// 파일이 없으면 생성
}
const sampleContent = `프로젝트명: 샘플 프로젝트
작성일: ${new Date().toISOString().split('T')[0].replace(/-/g, '.')}
회사명: Sample Company
작성자: 기획팀
=== 프로젝트 개요 ===
이것은 샘플 프로젝트입니다.
TXT → PPTX 변환 기능을 테스트하기 위한 예시 파일입니다.
=== 주요 기능 ===
1. 사용자 관리
- 회원 가입 및 로그인
- 프로필 관리
- 권한 설정
2. 콘텐츠 관리
- 게시글 작성 및 편집
- 파일 업로드
- 검색 기능
3. 시스템 관리
- 대시보드
- 설정 관리
- 로그 조회
=== 화면 구성 ===
메인 화면:
- 상단 네비게이션
- 콘텐츠 영역
- 사이드바
로그인 화면:
- 이메일 입력
- 비밀번호 입력
- 로그인 버튼
=== 기술 요구사항 ===
- 웹 기반 시스템
- 반응형 디자인
- 모바일 지원
- 클라우드 호스팅`;
try {
await fs.writeFile(samplePath, sampleContent, 'utf8');
this.printSuccess(`✅ 샘플 파일 생성됨: ${samplePath}`);
this.printInfo('💡 이제 다시 실행해보세요!');
} catch (error) {
this.printError(`샘플 파일 생성 실패: ${error.message}`);
}
}
/**
* 출력 유틸리티
*/
printSuccess(message) {
console.log(colors.green + message + colors.reset);
}
printInfo(message) {
console.log(colors.blue + message + colors.reset);
}
printError(message) {
console.log(colors.red + message + colors.reset);
}
printWarning(message) {
console.log(colors.yellow + message + colors.reset);
}
}
// 견적서 생성 함수
async function generateEstimate() {
try {
console.log(colors.cyan + '📊 SAM ERP 견적서 생성 중...' + colors.reset);
const { generateEstimatePPTX } = require('./estimate-pptx-generator.js');
const outputPath = await generateEstimatePPTX();
console.log(colors.green + `✅ 견적서 생성 완료: ${outputPath}` + colors.reset);
// 파일 크기 표시
const fs = require('fs').promises;
try {
const stats = await fs.stat(outputPath);
const sizeKB = (stats.size / 1024).toFixed(1);
console.log(colors.blue + `📏 파일 크기: ${sizeKB} KB` + colors.reset);
} catch (error) {
// 파일 크기 확인 실패 시 무시
}
} catch (error) {
console.log(colors.red + `❌ 견적서 생성 실패: ${error.message}` + colors.reset);
}
}
// 템플릿 기반 생성 함수
async function generateFromTemplate() {
try {
console.log(colors.cyan + '📋 템플릿 기반 PPTX 생성 중...' + colors.reset);
const { generateFromTemplate } = require('./.claude/skills/pdf-template-skill/scripts/generate-from-template.js');
const templatePath = 'templates/sam_estimate_template.json';
const dataPath = 'data/sample_estimate_data.json';
const outputPath = 'pptx/template_customized.pptx';
await generateFromTemplate(templatePath, dataPath, outputPath);
console.log(colors.green + `✅ 템플릿 기반 PPTX 생성 완료: ${outputPath}` + colors.reset);
// 파일 크기 표시
const fs = require('fs').promises;
try {
const stats = await fs.stat(outputPath);
const sizeKB = (stats.size / 1024).toFixed(1);
console.log(colors.blue + `📏 파일 크기: ${sizeKB} KB` + colors.reset);
} catch (error) {
// 파일 크기 확인 실패 시 무시
}
} catch (error) {
console.log(colors.red + `❌ 템플릿 기반 생성 실패: ${error.message}` + colors.reset);
}
}
// 대화형 실행 인터페이스
async function interactiveMode() {
const generator = new PPTGenerator();
console.log();
console.log(colors.cyan + '🎯 명령어 입력:' + colors.reset);
console.log(' • "ppt" 또는 "실행" - TXT → PPTX 변환');
console.log(' • "estimate" 또는 "견적서" - SAM ERP 견적서 생성');
console.log(' • "template" 또는 "템플릿" - 템플릿 기반 PPTX 생성');
console.log(' • "help" 또는 "도움말" - 도움말');
console.log(' • "exit" 또는 "종료" - 프로그램 종료');
console.log();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: colors.bright + '> ' + colors.reset
});
rl.prompt();
rl.on('line', async (input) => {
const command = input.trim().toLowerCase();
switch (command) {
case 'ppt':
case '실행':
await generator.run();
break;
case 'estimate':
case '견적서':
await generateEstimate();
break;
case 'template':
case '템플릿':
await generateFromTemplate();
break;
case 'help':
case '도움말':
showHelp();
break;
case 'exit':
case '종료':
case 'quit':
console.log(colors.green + '👋 프로그램을 종료합니다.' + colors.reset);
rl.close();
return;
case '':
// 빈 입력 무시
break;
default:
console.log(colors.yellow + '❓ 알 수 없는 명령어입니다. "help"를 입력하세요.' + colors.reset);
break;
}
rl.prompt();
});
rl.on('close', () => {
process.exit(0);
});
}
// 도움말 표시
function showHelp() {
console.log();
console.log(colors.cyan + colors.bright + '📖 TXT → PPTX 변환기 사용법' + colors.reset);
console.log();
console.log('🔹 기본 사용법:');
console.log(' 1. source 폴더에 txt 파일을 넣으세요');
console.log(' 2. "ppt" 또는 "실행" 명령어를 입력하세요');
console.log(' 3. 파일을 선택하고 변환을 실행하세요');
console.log();
console.log('🔹 txt 파일 형식:');
console.log(' - 프로젝트명: [제목]');
console.log(' - 작성일: [날짜]');
console.log(' - === 섹션 제목 ===');
console.log(' - 1. 번호 목록');
console.log(' - • 불릿 포인트');
console.log();
console.log('🔹 출력:');
console.log(' - pptx 폴더에 PowerPoint 파일 생성');
console.log(' - PDF 샘플과 동일한 구조');
console.log();
console.log('🔹 명령어:');
console.log(' • ppt, 실행 - TXT → PPTX 변환 실행');
console.log(' • estimate, 견적서 - SAM ERP 견적서 생성');
console.log(' • help, 도움말 - 이 도움말');
console.log(' • exit, 종료 - 프로그램 종료');
console.log();
}
// 메인 실행
async function main() {
const args = process.argv.slice(2);
// 명령행 인수가 있으면 직접 실행
if (args.length > 0) {
const command = args[0].toLowerCase();
if (['ppt', '실행', 'run'].includes(command)) {
const generator = new PPTGenerator();
await generator.run();
} else if (['help', '도움말', '--help'].includes(command)) {
showHelp();
} else {
console.log('사용법: node run.js [ppt|실행|help|도움말]');
}
} else {
// 대화형 모드
await interactiveMode();
}
}
// 직접 실행시
if (require.main === module) {
main().catch(error => {
console.error(colors.red + '❌ 실행 오류:', error.message + colors.reset);
process.exit(1);
});
}
module.exports = { PPTGenerator };