2174504b59
v2.2.162-163: 신규 /stocks analysis <심볼> (펀더멘털 + 1년 차트 + LLM 종합). - 6차원: 가치/수익성/안정성(부채비율)/추세(MA 정배열+224회복)/안전마진/RSI 진입 타이밍 - 신규 /stocks position [심볼] <총자산> <리스크%> <손절%> — 포지션 사이징 계산기 v2.2.164-165: /youtube info 3-tier 재설계 (사용자 피드백: 중복·이모지·표 깨짐). - 9개 섹션 → 4개 ## 섹션 (30초 요약 / 핵심 개념 / 깊이 분석 / 정리자 노트) - 헤더 이모지 전면 제거, 표 → bullet, 한 줄 요약 중복 제거 v2.2.166: /stocks analysis 매매 타점 신규 섹션 (사용자 매매 규칙 raw 데이터 적응). - 매수 진입(3순위 시나리오) / 손절 / 익절 / 관망 해제 트리거 - LLM이 실제 가격(MA값, 1년 고가, 60일 저점) 자동 채움 v2.2.167: /stocks analysis 분석 로직 정밀화 (사용자 피드백 5건). - MA224 3-state (passed/failed/notApplicable) — 추세 확립 종목 ❌ 오해 차단 - 낙폭과대 failReason 명시 — 인과 거꾸로 해석 차단 - 우선주(끝자리 5/7/9) 자동 감지 → 보통주 현재가 fetch → 할인율 계산 - 프롬프트 판단 절제 규칙 4건 (PBR 절대값 단정/거래량 미세변동/우선주 특이/오탈자) v2.2.168: 재패키징 (별개 Datacollect bridge 수정과 함께 깨끗한 설치본). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
348 lines
18 KiB
TypeScript
348 lines
18 KiB
TypeScript
/**
|
||
* `/youtube` slash command 의 LLM 입력 빌더 + 자막 변환 헬퍼.
|
||
* - formatHms / fullScriptFromSegments / bucketSegments — segment list 가공
|
||
* - YoutubeAnalysisMode — info/benchmark/both 라우팅 enum (slashRouter 가 사용)
|
||
* - buildInfoExtractionPrompt — *영상 내용(지식)* 카드 추출 프롬프트
|
||
* - build4LensPrompt — 영상 *제작 기법* (훅/구조/제작/CTR) 4-렌즈 분석 프롬프트
|
||
*
|
||
* 옛 코드: slashRouter.ts 의 320줄짜리 inline 블록. 분리해 (a) 두 프롬프트가 같은
|
||
* segment 변환 helper 를 자연스럽게 공유, (b) 새 모드 추가 시 한 파일만 수정,
|
||
* (c) 단위 테스트로 prompt 회귀 확인 가능.
|
||
*/
|
||
|
||
export function formatHms(totalSec: number): string {
|
||
if (!isFinite(totalSec) || totalSec <= 0) return '00:00';
|
||
const s = Math.floor(totalSec);
|
||
const h = Math.floor(s / 3600);
|
||
const m = Math.floor((s % 3600) / 60);
|
||
const sec = s % 60;
|
||
return h > 0
|
||
? `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`
|
||
: `${m}:${String(sec).padStart(2, '0')}`;
|
||
}
|
||
|
||
/**
|
||
* 영상 전체 자막을 30초 버킷으로 묶어 `[mm:ss] 문장…` 형태의 읽기 좋은 full script로 변환.
|
||
* YouTube 자동자막은 segment가 잘게 끊겨 그대로 나열하면 가독성이 나쁘므로 묶는다.
|
||
*/
|
||
export function fullScriptFromSegments(segments: any[] | undefined): string {
|
||
if (!segments || segments.length === 0) return '(자막 없음 — 자동 자막이 없는 영상일 수 있습니다.)';
|
||
const buckets = new Map<number, string[]>();
|
||
for (const seg of segments) {
|
||
const b = Math.floor((seg.start || 0) / 30);
|
||
const arr = buckets.get(b) || [];
|
||
arr.push(String(seg.text || '').trim());
|
||
buckets.set(b, arr);
|
||
}
|
||
return Array.from(buckets.entries())
|
||
.sort((a, b) => a[0] - b[0])
|
||
.map(([b, texts]) => `**[${formatHms(b * 30)}]** ${texts.join(' ').replace(/\s+/g, ' ').trim()}`)
|
||
.join('\n\n');
|
||
}
|
||
|
||
/**
|
||
* timestamped segments → 분 단위 버킷으로 묶은 "타임라인 뼈대" 텍스트.
|
||
* §2 구조 분석에서 LLM 토큰을 아낀다.
|
||
*/
|
||
export function bucketSegments(segments: any[] | undefined, bucketSec = 30): { time: string; text: string }[] {
|
||
if (!segments || segments.length === 0) return [];
|
||
const buckets = new Map<number, string[]>();
|
||
for (const seg of segments) {
|
||
const bucket = Math.floor(seg.start / bucketSec);
|
||
const arr = buckets.get(bucket) || [];
|
||
arr.push(String(seg.text || '').trim());
|
||
buckets.set(bucket, arr);
|
||
}
|
||
return Array.from(buckets.entries())
|
||
.sort((a, b) => a[0] - b[0])
|
||
.map(([bucket, texts]) => ({
|
||
time: formatHms(bucket * bucketSec),
|
||
text: texts.join(' ').replace(/\s+/g, ' ').trim().slice(0, 240),
|
||
}));
|
||
}
|
||
|
||
/** Astra `/youtube` 의 분석 모드. 사용자 입력 `mode:info|benchmark|both`. */
|
||
export type YoutubeAnalysisMode = 'info' | 'benchmark' | 'both';
|
||
|
||
/**
|
||
* 정보 추출(info) 모드 LLM 프롬프트 — 영상의 *내용·지식* 자체를 다룬다.
|
||
*
|
||
* 의도: build4LensPrompt 가 "이 영상을 어떻게 베껴 만들지" 의 벤치마킹 톤이라
|
||
* 튜토리얼·강의·뉴스·인터뷰·리뷰 같은 정보형 영상에서는 가치가 낮다. 이 함수는
|
||
* 정반대 방향 — 영상이 *말한 것* 을 사실·주장·근거 단위로 추출해서, 사용자가
|
||
* 영상을 안 다시 봐도 의사결정·학습·인용에 바로 쓸 수 있는 지식 카드로 정리한다.
|
||
*
|
||
* 출력 규칙은 build4LensPrompt 와 일관 (마크다운, 한국어, 자막에 있는 것만 인용).
|
||
*/
|
||
export function buildInfoExtractionPrompt(video: any, userContent: string): string {
|
||
const meta = video.metadata || {};
|
||
const segments = video.segments || [];
|
||
|
||
// 자막 본문 — info 모드는 *전체* 본문을 보여줘야 사실 추출이 정확. 단,
|
||
// LLM 컨텍스트 한도 고려해 너무 길면 trim. 12000자 = 가벼운 강의 60분 분량 정도.
|
||
const fullText = segments.map((s: any) => String(s.text || '').trim()).join(' ').replace(/\s+/g, ' ');
|
||
const trimmed = fullText.length > 12000 ? fullText.slice(0, 12000) + ' …[자막 일부 잘림]' : fullText;
|
||
|
||
const slim = {
|
||
url: meta.webpage_url || `https://www.youtube.com/watch?v=${video.video_id}`,
|
||
title: meta.title || video.title,
|
||
channel: meta.channel,
|
||
durationSec: meta.duration,
|
||
durationHms: meta.duration_string,
|
||
uploadDate: meta.upload_date,
|
||
viewCount: meta.view_count,
|
||
likeCount: meta.like_count,
|
||
tags: (meta.tags || []).slice(0, 8),
|
||
categories: meta.categories,
|
||
chapters: meta.chapters,
|
||
descriptionPreview: (meta.description || '').slice(0, 600),
|
||
};
|
||
|
||
const today = new Date().toISOString().slice(0, 10);
|
||
const userBlock = userContent.trim()
|
||
? `\n\n[사용자 컨텍스트 — 사용자가 어떤 관점에서 이 영상을 활용하려는지]\n${userContent.trim()}`
|
||
: '';
|
||
|
||
return `당신은 영상 콘텐츠를 *지식 카드*로 변환하는 정보 큐레이터입니다. 사장님이
|
||
이 영상을 다시 보지 않고도 핵심 정보를 그대로 활용할 수 있도록, 영상이 *말한 것*
|
||
(주장·사실·근거·결론)을 구조화해서 정리하세요.
|
||
|
||
[분석 원칙 — 모두 반드시 준수]
|
||
1. **출처 분리** — 영상 본문(자막)에 *명시된 것* 만 핵심 섹션에 넣음. 정리자의 추론·외부
|
||
지식·자기 해석은 별도 \`## 🧩 정리자 노트\` 섹션에만. 두 줄 섞지 말 것.
|
||
2. **빈 곳 채우지 말 것** — 자막에 없는 사실은 "본문에 명시되지 않음" 또는 "해당 사례 없음".
|
||
3. **신뢰도 라벨 필수** — 모든 핵심 주장 앞에 다음 중 하나:
|
||
- \`[근거 명시]\` 구체 출처·수치·인용이 본문에 있음
|
||
- \`[화자 주장]\` 출처 없는 단정 (디노가 그렇게 말함)
|
||
- \`[가정]\` 조건부·"~인 것 같다" 표현
|
||
- \`[정리자 추론]\` 본문에 없지만 정리자가 추가 (이건 정리자 노트 섹션 전용)
|
||
4. **타임스탬프 필수** — 본문 인용·구간 요약·발언 따옴표는 끝에 \`(mm:ss)\` 무조건 붙임.
|
||
이걸 빠뜨리면 fail. "(시점 미상)" 도 허용 안 함 — 모르면 인용 자체 빼기.
|
||
5. **화자 한 줄 비유 보존 + 방향 보존** — 영상에 비유·은유·"X 는 Y 같은 것" 식 압축 표현이
|
||
있으면 반드시 별도 섹션 \`## 💡 화자 한 줄 비유\` 에 보존. 영상의 결정적 요약이 거기
|
||
들어 있을 가능성 큼. 없으면 "본문에 명시된 한 줄 비유 없음" 명시.
|
||
⚠️ **비유는 방향이 뒤집히기 쉬움** — 화자가 "Hugging Face = 자료실, Reddit = 공부방"
|
||
이라 했으면 정확히 그 짝(어느 쪽이 자료실이고 어느 쪽이 공부방인지)을 그대로 따옴표
|
||
인용으로 보존. 정리자가 단어 위치를 바꾸거나 뜻을 의역하면 안 됨. 고유명사·수치·
|
||
대응 관계도 마찬가지 — 본문 그대로.
|
||
6. **순서·단계 발명 금지** — 화자가 "A → B → C 순서로" 라고 명시하지 *않았으면* "단계적
|
||
학습 순서" 같은 흐름을 정리자가 만들지 말 것. 굳이 필요하면 정리자 노트로.
|
||
7. 한국어 마크다운. **헤더에 이모지 금지** — 스캔할 때 시선이 분산되어 내용이 가려진다.
|
||
8. **표 사용 신중** — 모든 셀이 명확한 값으로 채워질 확신이 없으면 표 만들지 말고 bullet로. 깨진 셀(\`way\` 같은 LLM artifact)·빈 셀·"…" placeholder 절대 노출 금지.
|
||
9. **중복 금지** — 같은 내용은 한 곳에만. "한 줄 요약"이 여러 섹션에 반복되면 안 됨. 30초 요약에 한 번, 끝.
|
||
|
||
[영상 메타데이터]
|
||
\`\`\`json
|
||
${JSON.stringify(slim, null, 2)}
|
||
\`\`\`
|
||
|
||
[자막 본문]
|
||
${trimmed}${userBlock}
|
||
|
||
[필수 출력 형식 — 정확히 이 구조. 아래 4개 ## 섹션 외 추가 금지. 3-tier 깊이: ① 30초 요약(skim) → ② 핵심 개념(이해) → ③ 깊이 분석(deep dive). 읽는 사람이 목적에 따라 멈출 수 있게.]
|
||
|
||
# ${slim.title || video.title} — 정보 추출 카드
|
||
|
||
> **영상 URL**: ${slim.url} · **분석 일자**: ${today} · **길이**: ${slim.durationHms || (slim.durationSec ? formatHms(slim.durationSec) : '?')} · **채널**: ${slim.channel || '?'}
|
||
|
||
> 신뢰도 라벨: \`[근거 명시]\` 본문 출처/수치 · \`[화자 주장]\` 출처 없는 단정 · \`[가정]\` 조건부 · \`[정리자 추론]\` 정리자 노트 전용
|
||
|
||
---
|
||
|
||
## 30초 요약
|
||
|
||
*바쁜 사람은 여기서 멈춰도 영상을 안 본 것보다 낫게.*
|
||
|
||
- **한 줄**: 영상 전체를 한 문장으로 — "무엇이 누구에게 왜 중요한가". 화자 표현 기준, 정리자 의역 금지.
|
||
- **핵심 포인트 3개**: 영상이 *명시한* 결론·주장만 (정리자 추론 금지). 각 항목 신뢰도 라벨 + 한 줄 + 타임스탬프.
|
||
1. **[근거 명시]** ... — (mm:ss)
|
||
2. **[화자 주장]** ... — (mm:ss)
|
||
3. ... — (mm:ss)
|
||
- **화자 한 줄 비유** (있는 경우만): 화자가 *전체 메시지를 한 줄로 압축한 비유·은유* 그대로 따옴표.
|
||
⚠️ 방향 보존 필수 — "Hugging Face = 자료실, Reddit = 공부방" 같으면 짝과 순서를 본문 그대로. 정리자가 단어 위치를 바꾸거나 의역하면 안 됨. 고유명사·수치·대응관계도 본문 그대로.
|
||
예: "..." — (mm:ss). 본문에 비유 없으면 이 bullet 통째로 생략(line drop).
|
||
|
||
---
|
||
|
||
## 핵심 개념 설명
|
||
|
||
*개념을 이해하고 싶은 사람을 위해.*
|
||
|
||
영상이 다룬 *주요 개념·용어* 2-5개. 각각 정의 + 영상에서의 등장 맥락. 영상이 개념 위주가 아니라 사례·잡담·일화 위주면 이 ## 섹션 통째로 한 줄로 갈음: "이 영상은 개념보다 사례·주장 위주 — 핵심은 30초 요약 참조."
|
||
|
||
### {개념 이름 1}
|
||
- **정의**: 화자가 어떻게 정의했는지 (또는 일반 정의 + 화자 사용 방식).
|
||
- **영상에서**: "직접 인용" — (mm:ss). 등장 맥락 1-2문장.
|
||
|
||
### {개념 이름 2}
|
||
- **정의**: ...
|
||
- **영상에서**: ...
|
||
|
||
---
|
||
|
||
## 깊이 분석
|
||
|
||
*깊게 보고 싶은 사람을 위한 추가 자료.*
|
||
|
||
### 타임라인
|
||
영상 30분 이상이면 chapters(메타데이터에 있으면 사용) 또는 흐름 단위로 4-7개 구간 압축. 30분 미만이면 이 sub-section 통째로 한 줄: "영상이 짧아 생략."
|
||
- **[mm:ss–mm:ss]** 구간 핵심 한 문장
|
||
- ...
|
||
|
||
### 결정적 발언 (인용용)
|
||
글·발표·메모에 그대로 복붙 가능한 *한 문장 인용* 3-5개. 타임스탬프 필수. 위 30초 요약의 핵심 포인트와 중복되는 인용은 빼고, 보조 발언 위주로.
|
||
- "직접 인용 한 문장" — ${slim.channel || '?'} (mm:ss)
|
||
- ...
|
||
|
||
### 더 파고들 질문
|
||
영상이 답하지 않았거나 추가 검증 필요한 사항 2-4개. 사장님이 다음 자료를 찾을 때 검색어로 쓸 수 있게 구체적으로.
|
||
- "본문에서 X 가 Y 라고 했지만 Z 데이터 출처는 명시 안 됨 — 원 데이터 찾아볼 것"
|
||
- ...
|
||
|
||
### 구체 수치·데이터
|
||
**표 만들지 말 것** — bullet로, *완성된 정보만*. 본문에 모호하거나 정리자 추측이 들어가야 할 데이터는 통째로 생략. 항목: \`{이름}: {값} (mm:ss)\` 형태.
|
||
- ...
|
||
(본문에 명시된 구체 수치 없으면 이 sub-section 통째로 한 줄: "본문에 명시된 구체 수치 없음.")
|
||
|
||
---
|
||
|
||
## 정리자 노트 (선택)
|
||
|
||
*본문에 없지만* 정리자가 추가로 짚고 싶은 맥락·해석·연결·경고. 모두 \`[정리자 추론]\` 라벨로 시작 — 독자가 "이건 화자가 말한 게 아니라 LLM이 추론한 것"으로 즉시 식별.
|
||
- **[정리자 추론]** ...
|
||
- ...
|
||
|
||
보강할 게 없으면 이 ## 섹션 통째로 한 줄: "정리자 추가 노트 없음 — 본문 그대로가 명확함."`;
|
||
}
|
||
|
||
/**
|
||
* extract된 영상 → 유튜브 4-렌즈(훅/구조/제작/CTR) 분석 LLM 프롬프트.
|
||
* Datacollect 웹앱(YoutubePanel)의 build4LensPrompt를 그대로 이식.
|
||
*/
|
||
export function build4LensPrompt(video: any, userContent: string): string {
|
||
const meta = video.metadata || {};
|
||
const segments = video.segments || [];
|
||
|
||
// 초반 30초 / 60초 텍스트 — §1 훅 분석용.
|
||
const first30s = segments.filter((s: any) => s.start < 30).map((s: any) => String(s.text || '').trim()).join(' ').slice(0, 600);
|
||
const first60s = segments.filter((s: any) => s.start < 60).map((s: any) => String(s.text || '').trim()).join(' ').slice(0, 1200);
|
||
|
||
// 타임라인 버킷 (30초 단위) — §2 구조 분석용.
|
||
const timelineBuckets = bucketSegments(segments, 30);
|
||
const timelinePreview = timelineBuckets.slice(0, 24).map(b => `[${b.time}] ${b.text}`).join('\n');
|
||
|
||
// 인게이지먼트 키워드 매치 — §2 보조.
|
||
const engagementHits = segments
|
||
.filter((s: any) => /구독|좋아요|알림|댓글|공유|subscribe|like|comment/i.test(String(s.text || '')))
|
||
.slice(0, 5)
|
||
.map((s: any) => ({ t: formatHms(s.start), text: String(s.text || '').trim().slice(0, 100) }));
|
||
|
||
const slim = {
|
||
url: meta.webpage_url || `https://www.youtube.com/watch?v=${video.video_id}`,
|
||
title: meta.title || video.title,
|
||
channel: meta.channel,
|
||
durationSec: meta.duration,
|
||
durationHms: meta.duration_string,
|
||
viewCount: meta.view_count,
|
||
likeCount: meta.like_count,
|
||
commentCount: meta.comment_count,
|
||
uploadDate: meta.upload_date,
|
||
thumbnail: meta.thumbnail,
|
||
tags: (meta.tags || []).slice(0, 12),
|
||
categories: meta.categories,
|
||
chapters: meta.chapters,
|
||
descriptionPreview: (meta.description || '').slice(0, 600),
|
||
opening30s: first30s,
|
||
opening60s: first60s,
|
||
engagementMoments: engagementHits,
|
||
segmentCount: segments.length,
|
||
timelinePreview,
|
||
};
|
||
|
||
const today = new Date().toISOString().slice(0, 10);
|
||
const userBlock = userContent.trim()
|
||
? userContent.trim()
|
||
: '(미입력 — 일반 콘텐츠 제작자 컨텍스트로 작성)';
|
||
|
||
return `당신은 유튜브 '대본(스크립트)' 분석 전문가이자 콘텐츠 작가입니다. 사장님이
|
||
이 영상과 비슷한 콘텐츠의 **대본을 직접 쓰려** 합니다. 영상 연출이 아니라 오직
|
||
스크립트(텍스트)와 언어 구조만 분석해, 읽자마자 자기 대본에 복붙하듯 써먹을 수 있는
|
||
'유저 친화적 역기획서'를 작성하세요.
|
||
|
||
[분석 원칙]
|
||
1. BGM·자막·컷 전환·썸네일 등 대본만으로 알 수 없는 '영상 연출' 항목은 과감히 생략한다.
|
||
오직 스크립트(텍스트)와 언어 구조에만 집중한다.
|
||
2. 대사를 단순 인용하지 말고, 그 대사가 시청자 심리를 어떻게 건드렸는지 '언어적 장치'를
|
||
태그로 라벨링한다. 아래 태그 어휘에서만 골라 일관되게 사용한다:
|
||
#FOMO #권위부여 #호기심갭 #사회적증명 #페르소나 #약속Promise #공감후킹
|
||
#반전 #숫자강조 #문제고발 #브릿지멘트 #쉬운비유
|
||
3. 전문 용어가 나오면, 화자가 그것을 어떤 '쉬운 비유'나 일상어로 풀어 말했는지
|
||
그 구어체 '말의 맛'을 반드시 분석에 포함한다.
|
||
4. 한국어. 자막(text)·chapters·메타데이터에 있는 것만 인용(추측 금지). 타임스탬프는 mm:ss.
|
||
|
||
[영상 데이터]
|
||
\`\`\`json
|
||
${JSON.stringify(slim, null, 2)}
|
||
\`\`\`
|
||
|
||
[우리가 만들고 싶은 콘텐츠 / 채널 컨텍스트]
|
||
${userBlock}
|
||
|
||
[필수 출력 형식 — 정확히 이 구조. 아래 5개 섹션 외 추가 금지]
|
||
|
||
# ${slim.title || video.title} — 대본 역기획서
|
||
|
||
> **영상 URL**: ${slim.url} · **분석 일자**: ${today} · **길이**: ${slim.durationHms || (slim.durationSec ? formatHms(slim.durationSec) : '?')} · **채널**: ${slim.channel || '?'}
|
||
|
||
## 🎬 한 줄 인상 (One-line Read)
|
||
(이 영상 스크립트의 핵심 성격과 설득 전략을 한 줄로. 예: "전문 지식을 친구에게
|
||
설명하듯 풀어내고, 호기심 갭으로 끝까지 끌고 가는 정보형 대본")
|
||
|
||
## 1. 스크립트 뼈대 구조도 (Script Architecture)
|
||
구간별 마크다운 표 1개. '레퍼런스 실제 대사'는 자막에서 1문장 이내로 짧게 따옴표 인용.
|
||
'스크립트 기능'에는 위 태그 어휘를 1~2개 붙인다. 비중 %는 durationSec 기준,
|
||
chapters가 있으면 그것을, 없으면 timelinePreview로 구간을 추정.
|
||
|
||
| 구간 (비중) | 스크립트 기능 (태그) | 레퍼런스 실제 대사 | 벤치마킹 핵심 기술 |
|
||
| --- | --- | --- | --- |
|
||
| 오프닝 Hook (0:00~?, ?%) | #호기심갭 #약속Promise | "첫 대사…" | 결과를 미리 흘려 이탈 차단 |
|
||
| 도입부 (?~?, ?%) | … | … | … |
|
||
| 본론 (?~?, ?%) | … | … | … |
|
||
| 아웃트로·CTA (?~?, ?%) | … | … | … |
|
||
|
||
## 2. 말의 맛 & 톤앤매너 (Tone & Manner)
|
||
- **문장 길이 특징**: 단문/장문, 호흡, 리듬 — 실제 자막 예시 1개를 따옴표로.
|
||
- **어조 페르소나**: 예) 친근한 전문가체 / 단정적 신뢰체 — 근거 대사 1개.
|
||
- **핵심 대사 장치**: 시청자 중간 이탈을 막으려 대본 사이에 심은 미끼 문장·브릿지 멘트를
|
||
타임스탬프와 함께 2~3개 추출, 각각 태그 라벨을 붙인다.
|
||
- **전문용어 → 쉬운 비유**: 어려운 개념을 화자가 어떤 비유·일상어로 풀었는지
|
||
\`용어 → "화자의 실제 표현"\` 형태로 2~3개. 사례가 없으면 "해당 사례 없음"이라 명시.
|
||
|
||
## 3. 내 대본에 바로 쓰는 액션 체크리스트 (Action Items)
|
||
다음 대본을 쓸 때 무조건 적용할 행동 지침 3~4개. 반드시 체크박스로, 구체적 수치를 포함.
|
||
- [ ] (예: 오프닝 15초 안에 '내가 누구인지' 페르소나 한 문장 박기)
|
||
- [ ] …
|
||
- [ ] …
|
||
|
||
## ✂️ 빈칸 채우기식 대본 템플릿 (Fill-in-the-Blank)
|
||
레퍼런스의 말하기 구조·접속사·리듬은 그대로 살리고, 내 콘텐츠 내용만 [ ]에 채우면
|
||
대본이 완성되는 형태. 각 [ ] 안에는 무엇을 넣을지 짧은 힌트를 적는다.
|
||
|
||
\`\`\`
|
||
[오프닝 — Hook]
|
||
"여러분, 혹시 [시청자의 흔한 고민]… 해보신 적 있으세요?
|
||
오늘은 [이 영상이 줄 핵심 결과]를 [숫자]분 만에 끝내 드릴게요."
|
||
|
||
[도입부 — 공감 + 권위]
|
||
…
|
||
|
||
[본론 — 단계별 설명]
|
||
…
|
||
|
||
[아웃트로 — CTA]
|
||
…
|
||
\`\`\`
|
||
|
||
> ⚠️ 본 분석은 스크립트의 언어·구조 패턴 학습용입니다. 대사·자료는 직접 창작/라이선스 확보.`;
|
||
}
|