Files
Ex2-novel-agent/.claude/commands/rovel.seed.md
rupy1014 f66fe445bf Initial commit: Novel Agent setup
- Add 3 AI agents (writing, revision, story-continuity specialists)
- Add 4 slash commands (rovel.create, write, complete, seed)
- Add novel creation/writing rules
- Add Novelpia reference data (115 works, 3328 chapters)
- Add CLAUDE.md and README.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 21:31:57 +09:00

13 KiB

description
description
웹소설 챕터를 씬/라인 데이터로 변환하여 D1 시드 SQL 생성

User Input

$ARGUMENTS

User input must be considered (if not empty).

Overview

마크다운 원고를 인터랙티브 씬/라인 데이터로 변환하여 D1 시드 SQL을 생성합니다.

실행 방법:

  • /rovel.seed content/rovel/협회 소속 양호선생님/chapters/001.md (단일 파일)
  • /rovel.seed 협회 소속 양호선생님 1화 (작품명 + 화수)
  • /rovel.seed 협회 소속 양호선생님 1-8화 (범위)
  • /rovel.seed 협회 소속 양호선생님 전체 (모든 챕터)

워크플로우:

┌─────────────────────────────────────────────────────────┐
│  Phase 1: 입력 파싱                                      │
│  - 파일 경로 또는 작품명+화수 파싱                        │
│  - 작품 폴더 및 캐릭터 ID 매핑 로드                       │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 2: 마크다운 파싱                                  │
│  - 씬 구분 (*** 기준)                                    │
│  - 라인 타입 감지 (대화/나레이션/효과음 등)               │
│  - 시스템 카드 파싱                                      │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 3: 메타데이터 추출                                │
│  - 화자 추론 (컨텍스트 + 말투 분석)                      │
│  - 씬 정보 추출 (시간/장소/분위기)                       │
│  - is_playable 판정                                     │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 4: SQL 생성                                       │
│  - INSERT 문 생성                                        │
│  - 파일 저장 및 안내                                     │
└─────────────────────────────────────────────────────────┘

Phase 1: 입력 파싱

입력 유형 분석

Case A - 절대/상대 경로:
  입력: content/rovel/협회 소속 양호선생님/chapters/001.md
  해석: 해당 파일 직접 처리

Case B - 작품명 + 화수:
  입력: 협회 소속 양호선생님 3화
  해석: content/rovel/협회 소속 양호선생님/chapters/003.md

Case C - 작품명 + 범위:
  입력: 협회 소속 양호선생님 1-8화
  해석: 001.md ~ 008.md 순차 처리

Case D - 작품명 + 전체:
  입력: 협회 소속 양호선생님 전체
  해석: chapters/ 폴더의 모든 .md 파일

캐릭터 ID 매핑 로드

작품 폴더의 인물목록.md를 읽어 캐릭터 이름 → ID 매핑 생성:

매핑 생성 규칙:
  - 주인공 (한시우): char-{영문이름}-001
  - 히로인/주요 인물: char-{영문이름}-001
  - 조연: char-{영문이름}-001

예시 (협회 소속 양호선생님):
  한시우: char-hansiuw-001 (주인공)
  자화연: char-jahwayeon-001
  박준혁: char-parkjunhyuk-001
  김 과장: char-kimgwajang-001
  루나: char-luna-001

ID 체계

작품 ID: work-{작품영문코드}-001
  : work-yanghosam-001

챕터 ID: chapter-{3자리화수}
  : chapter-001, chapter-008

씬 ID: scene-{3자리화수}-{2자리순서}
  : scene-001-01, scene-008-03

라인 ID: line-{3자리화수}-{2자리씬순서}-{3자리라인순서}
  : line-001-01-001, line-008-03-015

시스템 카드 ID: syscard-{3자리화수}-{2자리씬순서}-{2자리순서}
  : syscard-001-02-01

Phase 2: 마크다운 파싱

라인 타입 감지 규칙

// 우선순위 순서로 적용
1.  줄만 있음  skip
2. `***`  divider ( 구분)
3. `[제목]`  시작 (, [다음 제외)  system (시스템 카드 시작)
4. `- `  시작  sfx (효과음)
5. `"`  시작하고 `"`  끝남  dialogue (대화)
6. `'`  시작하고 `'`  끝남  thought (속마음)
7.    narration (나레이션)

시스템 카드 파싱

입력:
[진맥 판독]
[대상: 박준혁, 28세, B급 헌터]
[외상: 좌측 어깨 베임 (깊이 1.2cm)]
[내상: 마력 과다 사용으로 인한 피로 누적]

출력:
{
  type: "diagnosis",
  title: "진맥 판독",
  content: [
    { label: "대상", value: "박준혁, 28세, B급 헌터" },
    { label: "외상", value: "좌측 어깨 베임 (깊이 1.2cm)" },
    { label: "내상", value: "마력 과다 사용으로 인한 피로 누적" }
  ],
  summary: "대상: 박준혁",
  isPlayable: true
}

시스템 카드 타입 매핑

제목 키워드 타입 isPlayable
진맥 판독, 분석, 스캔 diagnosis true
잠재력 분석 potential true
환자 심리 분석, 환자 상태 psychology true
은밀 치유 skill_active true
신규 기능 감지, 잠재 해방 skill_unlock false
경고, 숨겨진 warning false
일일 진료 현황, 권장 행동 info_update false
그 외 info_update false

Phase 3: 메타데이터 추출

화자 추론 규칙

1. 이전 3줄 컨텍스트 분석:
   "자화연이 고개를 들었다."
   "......" → speaker: char-jahwayeon-001

2. 대사 내 특징적 표현:
   "본좌" → 자화연
   "선생님" → 박준혁 (주인공에게 말할 때)

3. 주인공 여부:
   - 내면 독백 ('생각') → isProtagonist: true
   - "나는", "내가" 주어 → isProtagonist: true

씬 메타데이터 추출

시간 감지:
  - "밤 11시", "새벽 2시", "오후 5시" 
  - 첫 번째 매칭 사용

장소 감지:
  - "의무실", "협회", "던전" 등 키워드
  - 씬 첫 부분에서 추출

분위기 감지:
  - "살기", "긴장", "평온", "따뜻" 
  - 시스템 카드나 나레이션에서 추출

is_playable 판정

씬이 플레이 가능한 경우:
  1. isPlayable: true인 시스템 카드가 1개 이상
  2. 주요 캐릭터와의 대화 장면
  3. 선택지가 제시될 수 있는 상황

is_playable: true 조건:
  - diagnosis, potential, psychology, skill_active 타입 카드 존재
  - 주요 히로인과 첫 대면 장면

Phase 4: SQL 생성

출력 파일

단일 파일:
  입력: 001.md
  출력: 001-seed.sql

범위/전체:
  입력: 1-8화
  출력: chapters-seed.sql (병합된 파일)

SQL 템플릿

-- Chapter chapter-{NNN} scenes and lines
-- Auto-generated from markdown

-- Delete existing data for this chapter
DELETE FROM system_cards WHERE line_id IN (SELECT id FROM lines WHERE scene_id IN (SELECT id FROM scenes WHERE chapter_id = 'chapter-{NNN}'));
DELETE FROM lines WHERE scene_id IN (SELECT id FROM scenes WHERE chapter_id = 'chapter-{NNN}');
DELETE FROM scenes WHERE chapter_id = 'chapter-{NNN}';

-- 챕터가 없으면 생성
INSERT OR IGNORE INTO chapters (id, work_id, number, title, is_free, price, status, view_count, created_at, updated_at)
VALUES (
  'chapter-{NNN}',
  '{work_id}',
  {number},
  '{title}',
  {is_free},
  {price},
  'published',
  0,
  {timestamp},
  {timestamp}
);

-- Scene 1: {title}
INSERT INTO scenes (id, chapter_id, "order", title, location, time, mood, is_playable, play_description, character_ids, created_at) VALUES (
  'scene-{NNN}-{NN}',
  'chapter-{NNN}',
  {order},
  '{title}',
  '{location}',
  '{time}',
  '{mood}',
  {is_playable},
  '{play_description}',
  '{character_ids_json}',
  {timestamp}
);

-- Lines for scene {N}
INSERT INTO lines (id, scene_id, "order", type, content, speaker_id, is_protagonist, created_at) VALUES
  ('line-{NNN}-{NN}-{NNN}', 'scene-{NNN}-{NN}', {order}, '{type}', '{content}', {speaker_id}, {is_protagonist}, {timestamp}),
  ...;

-- System cards for scene {N}
INSERT INTO system_cards (id, line_id, type, title, content, summary, is_playable, choice_label, created_at) VALUES
  ('syscard-{NNN}-{NN}-{NN}', 'line-{NNN}-{NN}-{NNN}', '{type}', '{title}', '{content_json}', '{summary}', {is_playable}, '{choice_label}', {timestamp});

SQL 이스케이프 규칙

작은따옴표: ' → ''
줄바꿈: \n → 그대로 (TEXT 필드)
JSON: 쌍따옴표 사용, 이스케이프
NULL: speaker_id 없으면 NULL (문자열 'NULL' 아님)

실행 예시

예시 1: 단일 파일

/rovel.seed content/rovel/협회 소속 양호선생님/chapters/008.md

출력:

## 씬 변환 완료

**파일**: `content/rovel/협회 소속 양호선생님/chapters/008.md`
**챕터 ID**: chapter-008

### 생성된 데이터

| 항목 | 개수 |
|------|------|
| 씬 | 12개 |
| 라인 | 156개 |
| 시스템 카드 | 3개 |
| 플레이 가능 씬 | 2개 |

### 등장 캐릭터

| 캐릭터 | ID | 대사 수 |
|--------|-----|---------|
| 루나 | char-luna-001 | 24 |
| 한시우 | (주인공) | 18 |

### 생성된 SQL

**파일**: `content/rovel/협회 소속 양호선생님/chapters/008-seed.sql`

### 다음 단계

1. SQL 확인:
   cat content/rovel/협회 소속 양호선생님/chapters/008-seed.sql

2. 로컬 D1 적용:
   npx wrangler d1 execute rovel-db --local --file=content/rovel/협회 소속 양호선생님/chapters/008-seed.sql

3. 원격 D1 적용:
   npx wrangler d1 execute rovel-db --remote --file=content/rovel/협회 소속 양호선생님/chapters/008-seed.sql

예시 2: 범위 변환

/rovel.seed 협회 소속 양호선생님 1-8화

출력:

## 씬 변환 완료 (8개 챕터)

### 변환 결과

| 화수 | 씬 | 라인 | 시스템 카드 | 플레이 가능 |
|------|-----|------|-------------|-------------|
| 1화 | 12 | 89 | 2 | 1 |
| 2화 | 10 | 102 | 3 | 2 |
| ... | | | | |
| 8화 | 14 | 156 | 3 | 2 |
| **합계** | **92** | **1,024** | **18** | **12** |

### 생성된 SQL

**파일**: `content/rovel/협회 소속 양호선생님/chapters-seed.sql`

### 다음 단계

로컬 D1 적용:
npx wrangler d1 execute rovel-db --local --file=content/rovel/협회 소속 양호선생님/chapters-seed.sql

원격 D1 적용:
npx wrangler d1 execute rovel-db --remote --file=content/rovel/협회 소속 양호선생님/chapters-seed.sql

캐릭터 ID 매핑 (협회 소속 양호선생님)

주인공:
  한시우: char-hansiuw-001

히로인:
  자화연: char-jahwayeon-001
  루나: char-luna-001

조연:
  박준혁: char-parkjunhyuk-001
  김 과장: char-kimgwajang-001
  김수진: char-kimsujin-001

새 캐릭터 등장 시

인물목록.md에 없는 새 캐릭터가 등장하면:

  1. 경고 메시지 출력
  2. 임시 ID 생성 (char-{이름영문}-temp)
  3. 인물목록.md 업데이트 권장

Reference Files

유형 경로 용도
변환 가이드 rules/chapter-to-scene.md 마크다운 문법 참조
인물목록 content/rovel/{작품명}/인물목록.md 캐릭터 ID 매핑
기존 시드 scripts/seed-d1.sql SQL 형식 참조
DB 스키마 src/server/db/schema.ts 테이블 구조 참조

Important Notes

변환 시 주의사항

1. 캐릭터 ID 매핑:
   - 인물목록.md 먼저 확인
   - 없는 캐릭터는 경고 후 임시 ID

2. 시스템 카드:
   - [제목] 다음 줄들이 필드
   - 빈 줄이나 다른 타입 만나면 종료
   - JSON 형식으로 content 저장

3. 화자 추론:
   - 이전 컨텍스트 우선
   - 말투 패턴으로 보조
   - 불확실하면 NULL

4. SQL 이스케이프:
   - 작은따옴표는 ''로
   - NULL은 문자열 아닌 키워드

스키마 호환성

현재 스키마:
  - scenes.is_playable: 플레이 가능 여부
  - scenes.character_ids: JSON 배열
  - system_cards: lines.id로 연결

체크 필요:
  - works 테이블에 작품 존재 여부
  - characters 테이블에 캐릭터 존재 여부

작품별 설정

새 작품 추가 시:

  1. 작품 ID 결정 (work-{코드}-001)
  2. 캐릭터 ID 매핑 정의
  3. 인물목록.md에 캐릭터 정보 확인