---
name: text-analyzer-skill
description: 자연어 텍스트 파일을 분석하여 PDF 템플릿 구조에 매핑하는 스킬. 섹션 추출, 콘텐츠 분류, 구조화된 데이터 생성 기능 제공.
---

# Text Analyzer Skill - 자연어 텍스트 분석 스킬

source 폴더의 txt 파일을 분석하여 PDF 샘플과 동일한 형태의 PPTX로 변환하는 핵심 스킬입니다.

## 기능 개요

### 1. 자연어 텍스트 분석 (Natural Language Processing)
텍스트 파일의 구조와 내용을 자동으로 파싱하고 분류

### 2. PDF 템플릿 매핑 (Template Mapping)
분석된 내용을 SAM_ERP 스토리보드 구조에 자동 매핑

### 3. 구조화된 데이터 생성 (Structured Data Generation)
PPTX 생성에 필요한 슬라이드별 데이터 구조 생성

### 4. 콘텐츠 최적화 (Content Optimization)
프레젠테이션에 적합한 형태로 콘텐츠 가공

## 핵심 워크플로우

### 텍스트 분석 → PDF 구조 매핑 워크플로우

```mermaid
graph TD
    A[source/*.txt] --> B[텍스트 파싱]
    B --> C[섹션 인식]
    C --> D[콘텐츠 분류]
    D --> E[PDF 템플릿 매핑]
    E --> F[PPTX 데이터 생성]
    F --> G[슬라이드 변환]
```

### 자연어 분석 엔진

#### 1. 섹션 인식 패턴
```javascript
const SECTION_PATTERNS = {
  // 프로젝트 메타 정보
  project_meta: /^(프로젝트명|제목|title):\s*(.+)$/im,
  date: /^(작성일|날짜|date):\s*(.+)$/im,
  company: /^(회사명|회사|company):\s*(.+)$/im,
  author: /^(작성자|저자|author):\s*(.+)$/im,

  // 주요 섹션 구분
  overview: /^=+\s*(개요|프로젝트\s*개요|overview)\s*=+$/im,
  features: /^=+\s*(기능|주요\s*기능|features)\s*=+$/im,
  screens: /^=+\s*(화면|화면\s*구성|screens)\s*=+$/im,
  requirements: /^=+\s*(요구사항|기술\s*요구사항|requirements)\s*=+$/im,
  flow: /^=+\s*(플로우|사용자\s*플로우|flow)\s*=+$/im,

  // 하위 항목
  numbered_item: /^(\d+)\.\s*(.+)$/,
  bullet_item: /^[-*]\s*(.+)$/,
  sub_item: /^\s*[-*]\s*(.+)$/
};
```

#### 2. 콘텐츠 분류 규칙
```javascript
const CONTENT_CLASSIFIERS = {
  // 화면/기능 관련
  screen_indicators: ['화면', '페이지', '뷰', 'screen', 'page', 'view'],
  feature_indicators: ['기능', '모듈', '시스템', 'feature', 'module', 'system'],
  ui_indicators: ['버튼', '메뉴', '입력', '목록', 'button', 'menu', 'input', 'list'],

  // 비즈니스 로직
  business_indicators: ['관리', '분석', '처리', '생성', 'management', 'analysis'],
  data_indicators: ['데이터', '정보', '내역', 'data', 'information'],

  // 기술 요구사항
  tech_indicators: ['시스템', '플랫폼', '기술', 'system', 'platform', 'technology']
};
```

### PDF 템플릿 매핑 로직

#### SAM_ERP 구조 매핑 테이블
```javascript
const TEMPLATE_MAPPING = {
  // 표지 (Cover) - 1페이지
  cover: {
    source_fields: ['project_meta', 'date', 'company', 'author'],
    template_layout: 'brand_centered',
    required: true
  },

  // 문서 히스토리 - 2페이지
  document_history: {
    source_fields: ['date', 'author'],
    template_layout: 'table_full_width',
    auto_generate: true // 자동 생성
  },

  // 메뉴 구조 - 3페이지
  menu_structure: {
    source_fields: ['features', 'screens'],
    template_layout: 'hierarchical_diagram',
    extraction_method: 'feature_hierarchy'
  },

  // 공통 가이드라인 - 4-8페이지
  common_guidelines: {
    source_fields: ['requirements', 'ui_patterns'],
    template_layout: 'documentation_style',
    default_sections: ['interaction', 'responsive', 'template', 'notifications']
  },

  // 상세 화면 - 9-N페이지
  detail_screens: {
    source_fields: ['screens', 'features', 'flow'],
    template_layout: 'wireframe_with_description',
    per_screen: true
  }
};
```

## 스크립트 구조

### 1. text-parser.js
자연어 텍스트 파싱 및 구조 분석

```javascript
class TextParser {
  constructor() {
    this.sections = new Map();
    this.metadata = {};
  }

  async parseFile(filePath) {
    const content = await fs.readFile(filePath, 'utf8');
    return this.parseContent(content);
  }

  parseContent(content) {
    // 1. 메타데이터 추출
    this.extractMetadata(content);

    // 2. 섹션 구분
    this.extractSections(content);

    // 3. 구조화된 데이터 반환
    return {
      metadata: this.metadata,
      sections: this.sections,
      raw_content: content
    };
  }

  extractMetadata(content) {
    Object.entries(SECTION_PATTERNS).forEach(([key, pattern]) => {
      const match = content.match(pattern);
      if (match && key.includes('meta') || ['date', 'company', 'author'].includes(key)) {
        this.metadata[key] = match[2]?.trim();
      }
    });
  }

  extractSections(content) {
    const lines = content.split('\n');
    let currentSection = null;
    let currentContent = [];

    lines.forEach(line => {
      const sectionMatch = this.findSectionHeader(line);
      if (sectionMatch) {
        // 이전 섹션 저장
        if (currentSection) {
          this.sections.set(currentSection, this.processContent(currentContent));
        }
        currentSection = sectionMatch;
        currentContent = [];
      } else if (currentSection) {
        currentContent.push(line);
      }
    });

    // 마지막 섹션 저장
    if (currentSection) {
      this.sections.set(currentSection, this.processContent(currentContent));
    }
  }

  findSectionHeader(line) {
    for (const [key, pattern] of Object.entries(SECTION_PATTERNS)) {
      if (['overview', 'features', 'screens', 'requirements', 'flow'].includes(key)) {
        const match = line.match(pattern);
        if (match) return key;
      }
    }
    return null;
  }

  processContent(lines) {
    const processed = {
      raw: lines.join('\n'),
      items: [],
      structure: 'flat'
    };

    lines.forEach(line => {
      line = line.trim();
      if (!line) return;

      // 번호 목록
      const numberedMatch = line.match(SECTION_PATTERNS.numbered_item);
      if (numberedMatch) {
        processed.items.push({
          type: 'numbered',
          number: numberedMatch[1],
          content: numberedMatch[2],
          children: []
        });
        processed.structure = 'numbered';
        return;
      }

      // 불릿 목록
      const bulletMatch = line.match(SECTION_PATTERNS.bullet_item);
      if (bulletMatch) {
        if (processed.items.length > 0 && line.startsWith('  ')) {
          // 하위 항목
          const lastItem = processed.items[processed.items.length - 1];
          lastItem.children.push({
            type: 'sub_bullet',
            content: bulletMatch[1]
          });
        } else {
          processed.items.push({
            type: 'bullet',
            content: bulletMatch[1],
            children: []
          });
        }
        processed.structure = 'hierarchical';
        return;
      }

      // 일반 텍스트
      if (processed.items.length === 0) {
        processed.items.push({
          type: 'paragraph',
          content: line
        });
      } else {
        const lastItem = processed.items[processed.items.length - 1];
        if (lastItem.type === 'paragraph') {
          lastItem.content += ' ' + line;
        } else {
          processed.items.push({
            type: 'paragraph',
            content: line
          });
        }
      }
    });

    return processed;
  }
}
```

### 2. template-mapper.js
파싱된 데이터를 PDF 템플릿 구조에 매핑

```javascript
class TemplateMapper {
  constructor() {
    this.pdfTemplate = null;
    this.mappedData = {};
  }

  async loadPDFTemplate(templatePath) {
    const templateContent = await fs.readFile(templatePath, 'utf8');
    this.pdfTemplate = JSON.parse(templateContent);
  }

  mapToTemplate(parsedData) {
    const mapped = {
      metadata: this.generateMetadata(parsedData.metadata),
      slides: []
    };

    // 1. 표지 생성
    mapped.slides.push(this.createCoverSlide(parsedData.metadata));

    // 2. 문서 히스토리 생성
    mapped.slides.push(this.createDocumentHistorySlide(parsedData.metadata));

    // 3. 메뉴 구조 생성
    mapped.slides.push(this.createMenuStructureSlide(parsedData.sections));

    // 4. 공통 가이드라인 생성
    mapped.slides.push(...this.createCommonGuidelines());

    // 5. 상세 화면 생성
    mapped.slides.push(...this.createDetailScreens(parsedData.sections));

    return mapped;
  }

  createCoverSlide(metadata) {
    return {
      type: 'cover',
      slide_number: 1,
      layout: this.pdfTemplate.page_templates.find(t => t.type === 'cover').layout,
      content: {
        title: metadata.project_meta || '프로젝트 기획서',
        subtitle: '시스템 기획 및 설계',
        date: this.formatDate(metadata.date),
        company: metadata.company || 'Company Name',
        author: metadata.author || '작성자'
      }
    };
  }

  createDocumentHistorySlide(metadata) {
    return {
      type: 'document_history',
      slide_number: 2,
      layout: this.pdfTemplate.page_templates.find(t => t.type === 'document_history').layout,
      content: {
        title: 'Document History',
        table: [
          {
            date: this.formatDate(metadata.date),
            version: 'D1.0',
            main_content: '초안 작성',
            detailed_content: `${metadata.project_meta || '프로젝트'} 기획서 초안 작성`,
            mark: ''
          }
        ]
      }
    };
  }

  createMenuStructureSlide(sections) {
    const features = sections.get('features') || { items: [] };
    const screens = sections.get('screens') || { items: [] };

    // 기능과 화면 정보를 계층 구조로 변환
    const menuStructure = this.buildMenuHierarchy(features, screens);

    return {
      type: 'menu_structure',
      slide_number: 3,
      layout: this.pdfTemplate.page_templates.find(t => t.type === 'system_structure').layout,
      content: {
        title: 'Menu Structure',
        structure: menuStructure
      }
    };
  }

  buildMenuHierarchy(features, screens) {
    const structure = {
      root: '시스템 구조',
      children: []
    };

    // 주요 기능을 상위 카테고리로 설정
    features.items.forEach(feature => {
      if (feature.type === 'numbered' && feature.content) {
        const category = {
          name: feature.content,
          children: []
        };

        // 하위 항목이 있으면 추가
        if (feature.children && feature.children.length > 0) {
          feature.children.forEach(child => {
            category.children.push({
              name: child.content,
              leaf: true
            });
          });
        }

        structure.children.push(category);
      }
    });

    // 화면 정보도 추가
    if (screens.items.length > 0) {
      const screenCategory = {
        name: '화면 구성',
        children: []
      };

      screens.items.forEach(screen => {
        if (screen.content) {
          screenCategory.children.push({
            name: screen.content,
            leaf: true
          });
        }
      });

      structure.children.push(screenCategory);
    }

    return structure;
  }

  createCommonGuidelines() {
    // PDF 템플릿의 공통 가이드라인 구조를 사용
    return [
      {
        type: 'common_guidelines',
        slide_number: 4,
        content: {
          title: '공통',
          sections: ['사용자 인터랙션', '반응형 웹', '화면 템플릿', '알림 시스템']
        }
      }
    ];
  }

  createDetailScreens(sections) {
    const detailSlides = [];
    let slideNumber = 9; // 상세 화면은 9페이지부터 시작

    // 기능별로 상세 화면 생성
    const features = sections.get('features');
    const screens = sections.get('screens');
    const flow = sections.get('flow');

    if (features && features.items) {
      features.items.forEach(feature => {
        if (feature.type === 'numbered') {
          detailSlides.push(this.createDetailScreenFromFeature(feature, slideNumber));
          slideNumber++;
        }
      });
    }

    // 명시적인 화면 구성이 있다면 추가
    if (screens && screens.items) {
      screens.items.forEach(screen => {
        detailSlides.push(this.createDetailScreenFromScreen(screen, slideNumber));
        slideNumber++;
      });
    }

    return detailSlides;
  }

  createDetailScreenFromFeature(feature, slideNumber) {
    return {
      type: 'detail_screen',
      slide_number: slideNumber,
      layout: this.pdfTemplate.page_templates.find(t => t.type === 'detail_screen').layout,
      content: {
        header_info: {
          task_name: feature.content,
          version: 'D1.0',
          page_number: slideNumber,
          route: this.generateRoute(feature.content),
          screen_name: feature.content,
          screen_id: this.generateScreenId(feature.content)
        },
        wireframe: {
          type: 'feature_mockup',
          description: `${feature.content} 화면 구성`,
          elements: this.extractUIElements(feature)
        },
        descriptions: this.generateDescriptions(feature)
      }
    };
  }

  extractUIElements(feature) {
    const elements = [];

    // 자연어에서 UI 요소 추출
    if (feature.children && feature.children.length > 0) {
      feature.children.forEach((child, index) => {
        elements.push(`${index + 1}. ${child.content}`);
      });
    } else {
      // 기본 UI 요소 추가
      elements.push('1. 헤더 영역');
      elements.push('2. 메인 콘텐츠');
      elements.push('3. 액션 버튼');
    }

    return elements;
  }

  generateDescriptions(feature) {
    const descriptions = [];

    if (feature.children && feature.children.length > 0) {
      feature.children.forEach((child, index) => {
        descriptions.push({
          number: index + 1,
          title: this.extractTitle(child.content),
          description: child.content
        });
      });
    } else {
      descriptions.push({
        number: 1,
        title: feature.content,
        description: `${feature.content} 기능 구현 및 사용자 인터랙션 처리`
      });
    }

    return descriptions;
  }

  extractTitle(content) {
    // 콘텐츠에서 제목 추출 (첫 번째 단어 또는 구문)
    const words = content.split(' ');
    return words.length > 3 ? words.slice(0, 2).join(' ') : words[0];
  }

  generateRoute(screenName) {
    return '/' + screenName
      .toLowerCase()
      .replace(/\s+/g, '_')
      .replace(/[^a-z0-9가-힣_]/g, '');
  }

  generateScreenId(screenName) {
    return screenName
      .toLowerCase()
      .replace(/\s+/g, '_')
      .replace(/[^a-z0-9가-힣_]/g, '');
  }

  formatDate(dateStr) {
    if (!dateStr) {
      return new Date().toISOString().split('T')[0].replace(/-/g, '.');
    }
    return dateStr.replace(/-/g, '.');
  }

  generateMetadata(metadata) {
    return {
      title: metadata.project_meta || '프로젝트 기획서',
      version: 'D1.0',
      created_date: this.formatDate(metadata.date),
      author: metadata.author || '작성자',
      company: metadata.company || 'Company Name',
      source_file: 'source/*.txt'
    };
  }
}
```

## 사용법

### 1. 기본 실행
```bash
# source 폴더의 txt 파일 분석 및 PPTX 생성
node .claude/skills/text-analyzer-skill/scripts/txt-to-pptx.js

# 또는 간단 명령
npm run txt-to-ppt
```

### 2. 특정 파일 지정
```bash
node txt-to-pptx.js --input source/my_project.txt --output my_presentation.pptx
```

### 3. 템플릿 지정
```bash
node txt-to-pptx.js --template custom_template.json --input source/project.txt
```

## 품질 기준

### 텍스트 분석 정확도
- **섹션 인식률**: >90% (명시적 구분자 기준)
- **콘텐츠 분류**: >85% (키워드 매칭 기준)
- **구조 보존**: 원본 계층 구조 유지

### PDF 템플릿 매핑 일치도
- **레이아웃 일관성**: SAM_ERP 스토리보드와 95% 일치
- **섹션 완성도**: 필수 섹션 100% 포함
- **콘텐츠 적합성**: 프레젠테이션 형태로 최적화

## 확장 기능

### 다양한 텍스트 형식 지원
- Markdown 파일 (.md)
- Word 문서 (.docx)
- 구조화된 JSON (.json)

### AI 기반 콘텐츠 최적화
- 자동 요약 기능
- 키워드 추출
- 슬라이드 분량 최적화