AI AUTOMATION / LIVE DECK
제작자 류웅수
← → / SPACE / SWIPE
AI AUTOMATION WORKSHOP

AI 배웠는데,
이제 뭘 만들까?

원본 하나를 블로그·카드·쇼츠·릴스로 연결하는 실제 파이프라인

FINDWRITEVISUALMOVE
01 / 19
01 / START WITH ONE INPUT
링크를 던지고,
내 일에 어디 붙일지 묻습니다.

뉴스 · 사례 · 경쟁사 · 업무 화면 — 시작은 하나면 충분합니다.

02 / 19
02 / ONE SOURCE, MANY CHANNELS

검증된 블로그 본문 하나가
네 개의 채널로 확장됩니다.

01

키워드

독자의 질문

02

검증 원고

공통 원본

03

이미지

표지와 장면

04

블로그·카드

읽고 저장하기

05

쇼츠·릴스

보고 공유하기

채널마다 새로 쓰지 않습니다.검증된 원본을 변환합니다.
03 / 19
03 / WHY PIPELINE

왜 한 번에
만들지 않았을까?

ONE GIANT PROMPT어디서 틀렸는지
알 수 없다
실패하면 처음부터 다시
STAGED PIPELINE멈춘 지점부터
다시 간다
검증 · 재사용 · 재개가 가능
04 / 19
04 / KEYWORD

네이버 검색 결과와
내 블로그 통계를 비교해
오늘의 글감을 고릅니다.

01 / DAILY

당일 주제

미리 정한 분야

02 / SEARCH

검색 결과 분석

잘 노출되는 글의 구조

03 / MY DATA

내 통계 분석

일간 · 주간 · 월간 TOP

04 / SCORE

글감 점수

수요 · 경쟁 · 중복

선정 기준상위 글보다 높은 편집 점수를 노릴 글감을 고릅니다.
05 / 19
05 / WRITING

상위 노출 구조와 AI 인용 구조를
한 원고 안에 설계합니다.

01 / BENCHMARK

상위 글 기준

분량 · H2 · 검색 의도

02 / SOURCE

근거 수집

공식 · 전문 출처

03 / ANSWER

먼저 답하기

핵심 답변 · 구체 문장

04 / REWRITE

검증 · 재작성

누락 · 오류 · 반복

결과사람에게 읽히고 AI 답변에 인용되기 쉬운 원고
06 / 19
06 / IMAGE PIPELINE

글의 톤과 H2를 읽고
한 세트의 이미지를 만듭니다.

01 / TONE

본문 톤 분석

주제 · 분위기

02 / STYLE

스타일 1개

한 글에 하나

03 / COVER

표지 1장

글 전체 의미

04 / H2

H2당 1장

섹션별 다른 장면

05 / CHECK

중복 검사

겹친 이미지만 재생성

통일 원칙스타일은 같게 · 장면은 H2의 내용에 맞게
07 / 19
07 / PROMPT LIBRARY

바나나X에서 글의 톤에 맞는
이미지 프롬프트를 고릅니다.

01 / TONE

글의 톤

정보 · 감성 · 전문

02 / STYLE

스타일 탐색

300개+ 프롬프트

03 / COPY

프롬프트 복사

원하는 카드 선택

04 / PASTE

생성기에 적용

내용과 톤 맞추기

바나나X이미지 생성기가 아니라 프롬프트를 고르는 곳
08 / 19
08 / IMAGE GENERATION MODEL

이미지를 실제로 만드는
생성 모델은 따로 있습니다.

THEN

Imagen 4 Fast
Nano Banana

주 엔진 실패 시 폴백

NOW

Codex 내장
이미지 생성

조용한 실패와 인증 경로를 줄임

역할 구분바나나X는 프롬프트 · 생성 모델은 이미지 제작
09 / 19
09 / BLOG-READY HTML

글과 이미지를 묶어
블로그용 HTML로 만듭니다.

01

검증된 글

제목 · 본문 · 소제목

02

이미지 배치

표지 · 본문 위치

03

HTML 변환

글과 이미지 결합

04

블로그에 붙여넣기

레이아웃 그대로

왜?블로그에서 글과 이미지 배치를 다시 만들지 않기 위해서입니다.
10 / 19
10 / BLOG DELIVERY

파일이 생겼다고
발행된 것은 아닙니다.

01

검증 원고

현재 버전

02

이미지 삽입

표지 · H2

03

HTML 변환

공개 형식

04

공개 확인

사이트 · 네이버

완료 기준실제 공개 화면에서 제목과 이미지를 확인합니다.
11 / 19
11 / INSTAGRAM CARDS

인스타 원고를 다시 쓰지 않고
블로그 본문을 메타데이터로 씁니다.

검증된 블로그 원본을 인스타그램 카드로 변환한 전체 카드 시트
12 / 19
12 / SHORTS
블로그 원본을 세로 쇼츠로 변환한 영상 썸네일
블로그 본문을 다섯 단계로
쇼츠 영상으로 바꿉니다.
01대본 만들기H1 · H2 분석
02첫 장면 영상화Grok
03세로 화면 · 자막9:16 구성
04내레이션 생성ElevenLabs · Google TTS
05영상 합성 · 업로드음악 → MP4 → YouTube
13 / 19
13 / REELS

쇼츠에서 만든 MP4가
릴스의 영상 원본이 됩니다.

13 / SHORTS OUTPUT쇼츠 영상
MP4 완성
장면 · 음성 · 자막 · 음악 포함
14 / REELS PUBLISH인스타 게시글 문구를
붙여 릴스로 게시
영상 아래 설명글 · 핵심 내용 · 해시태그
14 / 19
14 / ISOLATE THE FAILURE

한 채널의 실패가
전체를 망치지 않게 합니다.

SHARED SOURCE

원본은 공유

글과 이미지는 한 번 검증

중복 제작 방지
SEPARATE PROOF

발행은 개별 확인

블로그 · 카드 · 쇼츠 · 릴스

실패 범위 격리
15 / 19
15 / BUILD THE FLOW
한 번 만들고,
끝까지 이어갑니다.

링크 하나 → 질문 → 검증 원본 → 블로그 · 카드 · 쇼츠 · 릴스

좋은 자동화는 많이 만드는 게 아니라, 다시 시작하지 않게 만드는 것입니다.ONE SOURCE → MANY CHANNELS
16 / 19
16 / FINAL PRACTICE

블로그가 없어도
관심 분야만 있으면 시작할 수 있습니다.

01 / TOPIC

관심 분야

쓰고 싶은 분야 3~4개

02 / READER

읽을 사람

도움받을 독자 1명

03 / KEYWORD

키워드 후보

분야마다 3개씩

04 / BOARD

글감 보드

추천 · 후보 · 보류

실습내 관심사를 오늘 쓸 수 있는 제목으로 바꾸기 · 참고 보드 열기 ↗
17 / 19
17 / TRY FIRST

먼저 내 방식으로
만들어보세요.

PROMPT ONLY / 먼저 도전하기
이 프롬프트와 함께 제공한 Python 코드를 참고해서, 내 관심 분야와 대상 독자에 맞는 네이버 블로그 키워드 대시보드를 만들어줘.
네이버 상위 글을 실제로 확인하고 콘텐츠 빈틈과 AI 인용 구조까지 분석한 뒤, 코드를 실행해 HTML을 만들고 브라우저에서 화면도 검증해줘.

단, 지금 샘플을 그대로 만들지 말고 먼저 나에게 필요한 정보를 질문해줘.
질문과 답변이 끝나기 전에는 코드 수정이나 대시보드 생성을 시작하지 마.

[먼저 나에게 질문할 내용]
1. 앞으로 쓰고 싶은 관심 분야 3개는 무엇인가?
2. 각 분야에서 가장 먼저 도움을 주고 싶은 독자는 누구인가?
3. 독자가 겪는 문제나 자주 묻는 질문은 무엇인가?
4. 내가 직접 제공할 수 있는 경험, 사진, 비용, 비교표, 사례는 무엇인가?
5. 정보형·비교형·방법형·후기형 중 만들고 싶은 콘텐츠는 무엇인가?
6. 대시보드를 매일 쓸지, 한 번만 만들지, 주기적으로 업데이트할지?
7. 원하는 색상, 분위기, 꼭 넣을 항목과 빼고 싶은 항목은 무엇인가?

질문은 한 번에 보기 좋게 정리해서 물어보고, 내가 답하기 어려운 항목에는 선택지와 예시를 제시해줘.
내 답을 받은 다음에는 바로 만들지 말고 아래 순서로 먼저 제안해줘.

[맞춤 설계 순서]
1. 참고 보드와 Python 코드에서 유지할 기능, 바꿀 기능, 제외할 기능을 나눠 설명해줘.
2. 내 답변을 바탕으로 대시보드의 분야, 독자, 키워드 구조, 화면 구성을 다시 설계해줘.
3. 샘플의 여행·운동·재테크 키워드를 그대로 쓰지 말고 전부 내 관심 분야에 맞게 교체해줘.
4. 추천한 구조를 나에게 짧게 확인받은 뒤 네이버 조사와 코드 수정을 시작해줘.

너는 네이버 블로그 키워드 분석가이자 웹 디자이너야.
아직 블로그가 없는 초보자도 ‘무엇을 먼저 쓸지’ 판단할 수 있는 맞춤형 키워드 대시보드를 만들어줘.

[내 답변을 반영할 항목]
- 관심 분야 3개
- 분야별 주 독자와 해결할 문제
- 내가 제공할 수 있는 경험·자료
- 원하는 콘텐츠 유형과 업데이트 방식
- 원하는 화면 분위기와 필수 항목
- 참고 화면: https://sia-ian.vercel.app/viz/2026-07-23-blog-keyword-board

[1단계 — 키워드 후보 만들기]
1. 관심 분야마다 검색 의도가 분명한 세부 키워드를 4개씩, 총 12개 만들어줘.
2. 너무 넓은 한 단어보다 ‘대상 + 상황 + 궁금증’이 드러나는 키워드를 우선해줘.
3. 정보형, 비교형, 방법형, 후기형이 한쪽에 몰리지 않게 섞어줘.
4. 실제 검색량·상승률을 확인하지 못하면 숫자를 만들지 말고 ‘확인 필요’라고 표시해줘.

[2단계 — 네이버 상위 글 비교]
1. 각 키워드를 네이버에서 검색하고 현재 화면에 노출된 블로그 글 중 관련성이 높은 상위 5개를 확인해줘.
2. 글마다 제목, 작성일, 검색 의도, 주요 H2, 포함한 사례·숫자·표, 사용한 출처를 정리해줘.
3. 5개 글에서 반복되는 공통 내용과 아직 충분히 답하지 않은 질문을 분리해줘.
4. 상위 글을 복제하지 말고 ‘공통으로 꼭 답할 내용 + 빠진 내용 + 내가 더할 경험이나 공식 근거’로 차별화 방향을 제안해줘.
5. 네이버의 비공개 공식 점수를 추측하지 말고 아래 자체 편집 평가 점수만 사용해줘.
   - 검색 의도 충족 25점
   - 내용의 완결성 20점
   - 공식 근거와 출처 20점
   - 최신성 15점
   - 읽기 쉬운 구조 10점
   - 경험·사례 차별화 10점
6. 상위 5개 평균과 비교해 내가 보강해야 할 항목을 구체적으로 보여줘.
7. 웹 검색이 불가능하면 본 것처럼 꾸미지 말고 네이버 검색 결과 링크나 캡처를 요청해줘.

[3단계 — AI 인용 가능성 설계]
1. 각 추천 키워드마다 AI가 답변에 인용하기 쉬운 원고 구조를 설계해줘.
2. 첫 문단은 2~3문장으로 질문에 바로 답하는 ‘답변형 첫 문장’을 작성해줘.
3. H2는 독자가 실제로 묻는 질문 4~6개로 구성해줘.
4. 정의, 대상, 조건, 날짜, 숫자, 단위, 비교 기준을 생략하지 말아줘.
5. 정부기관·공식 문서·전문기관을 우선 찾아 출처명, 문서명, URL, 확인 날짜를 기록해줘.
6. 사실·경험·의견을 구분하고 확인되지 않은 수치와 존재하지 않는 출처는 만들지 말아줘.
7. 표, 단계, 체크리스트, 핵심 요약처럼 한 문단만 떼어도 뜻이 통하는 형식을 제안해줘.
8. 아래 자체 AI 인용 준비 점수를 계산하되 공식 평가 기준이라고 표현하지 말아줘.
   - 직접 답변 20점
   - 명확한 정의·조건 15점
   - 공식 출처 25점
   - 표·목록 구조 15점
   - 최신 날짜 10점
   - 출처 표시와 사실 구분 15점

[4단계 — 오늘 추천 3개 선정]
1. 검색 의도, 상위 글의 빈틈, 내가 더할 수 있는 경험, 공식 출처 확보 가능성을 함께 보고 3개를 골라줘.
2. 각 추천에 ‘왜 지금 쓰는지’, ‘상위 글보다 무엇을 더할지’, ‘AI 인용을 위해 무엇을 넣을지’를 한 줄씩 적어줘.
3. 바로 쓰기 어려운 키워드는 억지로 추천하지 말고 후보 또는 보류로 분류해줘.

[5단계 — 대시보드 화면]
1. 첫 화면에 오늘 추천 3개와 선정 이유를 가장 크게 보여줘.
2. 추천 카드마다 제목 2개, 네이버 상위 글 공통점, 콘텐츠 빈틈, 내 차별화, 편집 평가 점수, AI 인용 준비 점수를 표시해줘.
3. 추천 카드 아래에 답변형 첫 문장, 질문형 H2, 필요한 공식 출처를 보여줘.
4. 나머지 9개는 ‘지금 쓰기 / 후보 / 보류’ 상태와 함께 간결한 카드로 정리해줘.
5. 조사하지 못한 값은 ‘확인 필요’, 출처가 없는 값은 ‘출처 필요’라고 명확히 표시해줘.

[디자인과 기술 조건]
- 배경은 밝은 아이보리, 글자는 진한 회색, 강조색은 벽돌색으로 해줘.
- 컴퓨터에서는 3열, 작은 화면에서는 1열로 바뀌게 해줘.
- 외부 라이브러리 없이 HTML 안에 CSS와 JavaScript를 모두 넣어줘.
- 긴 분석은 접기/펼치기로 숨겨 첫 화면이 복잡하지 않게 해줘.
- 가로 스크롤, 글자 잘림, 카드 겹침이 없도록 브라우저에서 확인해줘.

[최종 출력]
1. 조사 결과를 구조화한 데이터
2. 실행 가능한 keyword_dashboard.html 전체 코드
3. 오늘 추천 3개와 선정 이유 요약
4. 확인하지 못한 항목과 추가로 필요한 자료 목록

설명만 하지 말고 실제 파일을 만들고 브라우저에서 열어 화면까지 검증해줘.
프롬프트만 전달합니다. 수강생이 코덱스의 질문에 답하며 자기 대시보드를 직접 만들어봅니다.
18 / 19
18 / RESCUE GIFT

막히면 이 선물을
열어보세요.

GIFT PACK / 프롬프트 + Python 코드
from datetime import date
from html import escape
from pathlib import Path
from urllib.parse import quote
import webbrowser

DASHBOARD_TITLE = "나의 네이버 블로그 키워드 보드"
OPEN_NAVER_SEARCH_TABS = False

# 검색량이나 네이버 공식 점수가 아닙니다.
# priority는 오늘 무엇부터 조사할지 정하는 개인 우선순위입니다.
KEYWORDS = [
    {"category":"여행","keyword":"서울 근교 당일치기","priority":92,"status":"지금 쓰기",
     "titles":["서울 근교 당일치기 실패 없는 5곳","차 없이 가는 서울 근교 하루 코스"]},
    {"category":"여행","keyword":"혼자 여행 준비물","priority":82,"status":"후보",
     "titles":["혼자 여행 처음이라면 챙길 7가지","1박 2일 혼자 여행 준비물 체크리스트"]},
    {"category":"여행","keyword":"비 오는 날 여행","priority":72,"status":"후보",
     "titles":["비 오는 날에도 좋은 국내 여행지","우천 여행에서 실패하지 않는 동선 짜기"]},
    {"category":"여행","keyword":"아이와 당일치기","priority":66,"status":"보류",
     "titles":["아이와 당일치기 준비물 7가지","두 시간 이동으로 끝내는 가족 나들이"]},
    {"category":"운동","keyword":"초보 러닝 30분","priority":89,"status":"지금 쓰기",
     "titles":["초보 러닝 30분을 버티는 가장 쉬운 방법","러닝 첫 달에 무릎을 지키는 5가지"]},
    {"category":"운동","keyword":"러닝화 고르는 법","priority":80,"status":"후보",
     "titles":["초보 러닝화는 쿠션만 보면 안 되는 이유","발볼과 거리에 맞는 러닝화 선택법"]},
    {"category":"운동","keyword":"아침 스트레칭","priority":70,"status":"후보",
     "titles":["아침 10분 전신 스트레칭 순서","허리가 뻐근한 날 시작하는 5동작"]},
    {"category":"운동","keyword":"운동 습관 만들기","priority":62,"status":"보류",
     "titles":["운동을 3일 만에 포기하지 않는 방법","일주일 운동 계획을 작게 시작하는 법"]},
    {"category":"재테크","keyword":"월급 통장 쪼개기","priority":86,"status":"지금 쓰기",
     "titles":["월급날 바로 끝내는 통장 쪼개기","통장 4개로 생활비 새는 돈 막는 법"]},
    {"category":"재테크","keyword":"초보 가계부","priority":77,"status":"후보",
     "titles":["가계부 3일 만에 포기하지 않는 방법","처음 쓰는 가계부에 필요한 항목 5개"]},
    {"category":"재테크","keyword":"비상금 만들기","priority":68,"status":"후보",
     "titles":["월 10만원으로 비상금 시작하는 순서","비상금 통장을 따로 둬야 하는 이유"]},
    {"category":"재테크","keyword":"고정비 줄이기","priority":60,"status":"보류",
     "titles":["한 달 고정비를 줄이는 점검표","구독 서비스 정리로 새는 돈 막는 법"]},
]

# 18페이지 프롬프트로 조사한 결과를 아래에 붙여 넣으세요.
# 점수는 네이버 공식 점수가 아니라 수강생이 사용하는 자체 평가 점수입니다.
ANALYSIS = {
    "서울 근교 당일치기": {
        "top_patterns": ["장소 목록 중심", "교통·비용 정보가 글마다 다름", "주말 혼잡도 설명이 짧음"],
        "content_gap": "출발 시간별 동선, 실제 총비용, 우천 대안이 부족함",
        "difference": "직접 이동 시간표와 1인 총비용표를 추가",
        "editorial": {"intent":23,"coverage":18,"evidence":17,"freshness":14,"structure":9,"experience":9},
        "citation": {"answer":18,"definition":14,"sources":21,"format":14,"freshness":9,"attribution":14},
        "answer_first": "서울 근교 당일치기는 이동 2시간 이내, 현지 체류 5시간 이상이 확보되는 곳부터 고르면 실패가 적습니다.",
        "h2": ["차 없이 갈 수 있는 곳은 어디인가?","교통비와 입장료는 얼마인가?","비가 오면 어떤 코스로 바꾸나?","아이와 갈 때 무엇을 확인해야 하나?"],
        "sources": [{"name":"공식 관광·교통 자료 URL을 입력하세요","url":""}]
    },
    "초보 러닝 30분": {
        "top_patterns": ["운동 루틴은 많음", "부상 위험 설명이 짧음", "개인 체력 기준이 모호함"],
        "content_gap": "걷기·달리기 비율과 중단 신호를 함께 설명한 글이 부족함",
        "difference": "주차별 강도표와 통증 발생 시 중단 기준을 추가",
        "editorial": {"intent":24,"coverage":18,"evidence":18,"freshness":13,"structure":9,"experience":8},
        "citation": {"answer":19,"definition":14,"sources":22,"format":14,"freshness":8,"attribution":14},
        "answer_first": "처음부터 30분을 계속 달리기보다 걷기와 달리기를 번갈아 총 30분을 채우는 방식이 안전합니다.",
        "h2": ["첫 주에는 몇 분씩 달려야 하나?","숨이 차면 어느 강도까지 괜찮나?","무릎 통증이 생기면 언제 멈춰야 하나?","신발과 준비운동은 무엇이 필요한가?"],
        "sources": [{"name":"공공 체육·의학 자료 URL을 입력하세요","url":""}]
    },
    "월급 통장 쪼개기": {
        "top_patterns": ["통장 개수 제안이 다름", "실제 금액 예시가 적음", "자동이체 날짜 설명이 부족함"],
        "content_gap": "월급 수준별 배분 예시와 실패했을 때 수정법이 부족함",
        "difference": "세후 월급별 예산표와 자동이체 순서를 추가",
        "editorial": {"intent":23,"coverage":19,"evidence":17,"freshness":14,"structure":9,"experience":8},
        "citation": {"answer":18,"definition":15,"sources":21,"format":15,"freshness":9,"attribution":14},
        "answer_first": "통장 쪼개기는 월급, 고정비, 생활비, 비상금 네 흐름을 분리하고 월급날 자동이체하는 방식으로 시작하면 됩니다.",
        "h2": ["통장은 꼭 4개가 필요한가?","월급날 무엇부터 이체해야 하나?","생활비는 얼마로 정해야 하나?","한 달 실패하면 어떻게 조정하나?"],
        "sources": [{"name":"공식 금융교육 자료 URL을 입력하세요","url":""}]
    }
}

def naver_url(keyword):
    return "https://search.naver.com/search.naver?where=blog&query=" + quote(keyword)

def score(values):
    return sum(values.values())

def list_html(items):
    return "".join(f"<li>{escape(item)}</li>" for item in items)

def source_html(sources):
    rows = []
    for source in sources:
        name, url = source["name"], source["url"]
        if url:
            rows.append(f'<li><a href="{escape(url)}" target="_blank">{escape(name)}</a></li>')
        else:
            rows.append(f'<li class="need">{escape(name)} · 출처 필요</li>')
    return "".join(rows)

def compact_card(item):
    return f"""
    <article class="card compact">
      <div class="card-top"><span>{escape(item["category"])}</span><b>{escape(item["status"])}</b></div>
      <h3>{escape(item["keyword"])}</h3>
      <p>개인 우선순위 {item["priority"]} · 검색량 확인 필요</p>
      <ul>{list_html(item["titles"])}</ul>
      <a class="search" href="{naver_url(item["keyword"])}" target="_blank">네이버 상위 글 확인 ↗</a>
    </article>"""

def detail_card(item):
    info = ANALYSIS[item["keyword"]]
    editorial_score = score(info["editorial"])
    citation_score = score(info["citation"])
    return f"""
    <article class="detail-card">
      <div class="card-top"><span>{escape(item["category"])} · {escape(item["keyword"])}</span><b>{escape(item["status"])}</b></div>
      <h3>{escape(item["titles"][0])}</h3>
      <div class="scores">
        <span>자체 편집 평가 <b>{editorial_score}/100</b></span>
        <span>AI 인용 준비 <b>{citation_score}/100</b></span>
      </div>
      <div class="analysis-grid">
        <div><small>상위 글 공통점</small><ul>{list_html(info["top_patterns"])}</ul></div>
        <div><small>콘텐츠 빈틈</small><p>{escape(info["content_gap"])}</p></div>
        <div><small>내 차별화</small><p>{escape(info["difference"])}</p></div>
      </div>
      <details>
        <summary>AI 인용 설계 펼치기</summary>
        <h4>답변형 첫 문장</h4><p class="answer">{escape(info["answer_first"])}</p>
        <h4>질문형 H2</h4><ol>{list_html(info["h2"])}</ol>
        <h4>공식 출처</h4><ul>{source_html(info["sources"])}</ul>
      </details>
      <a class="search" href="{naver_url(item["keyword"])}" target="_blank">네이버 상위 5개 다시 확인 ↗</a>
    </article>"""

top_three = sorted(
    [item for item in KEYWORDS if item["keyword"] in ANALYSIS],
    key=lambda item: item["priority"], reverse=True
)[:3]
top_html = "".join(detail_card(item) for item in top_three)

sections = []
for category in sorted({item["category"] for item in KEYWORDS}):
    items = [item for item in KEYWORDS if item["category"] == category]
    sections.append(
        f'<section class="panel"><h2>{escape(category)}</h2>'
        f'<div class="grid">{"".join(compact_card(item) for item in items)}</div></section>'
    )
section_html = "".join(sections)

page = f"""<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>{escape(DASHBOARD_TITLE)}</title>
  <style>
    *{{box-sizing:border-box}} body{{margin:0;background:#f6f3ee;color:#202124;font-family:-apple-system,BlinkMacSystemFont,"Noto Sans KR",sans-serif;line-height:1.55}}
    main{{max-width:1120px;margin:auto;padding:46px 20px 80px}} header{{padding-bottom:24px;border-bottom:1px solid #d9d1c8}}
    .eyebrow{{color:#a14632;font-size:12px;font-weight:800;letter-spacing:.12em}} h1{{margin:8px 0;font-size:40px;line-height:1.1}} .sub{{color:#6d665f}}
    .stats,.grid,.analysis-grid{{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}} .stats{{margin-top:24px}}
    .stat,.panel,.card,.detail-card{{background:#fff;border:1px solid #e4dbd1;border-radius:12px}} .stat{{padding:18px}} .stat b{{display:block;font-size:26px}}
    .panel{{margin-top:18px;padding:20px}} .panel h2{{margin:0 0 14px}} .decision{{border-color:#cbb7a5;background:#fffdf9}}
    .card,.detail-card{{padding:17px;background:#fffaf4}} .detail-card{{margin-top:14px;background:#fff}}
    .card-top{{display:flex;justify-content:space-between;gap:12px;font-size:12px;color:#796e65}} .card-top b{{color:#8b2f1f;background:#f4ded3;padding:3px 8px;border-radius:999px}}
    h3{{font-size:21px;margin:14px 0 7px}} p{{color:#5f5953}} ul,ol{{padding-left:18px}} .compact p,.compact li{{font-size:13px}}
    .scores{{display:flex;gap:10px;flex-wrap:wrap;margin:14px 0}} .scores span{{background:#f0ebe4;padding:8px 10px;border-radius:8px;font-size:13px}} .scores b{{color:#a14632}}
    .analysis-grid{{margin-top:14px}} .analysis-grid div{{border-top:2px solid #d5c1af;padding-top:10px}} .analysis-grid small{{color:#a14632;font-weight:800}}
    .analysis-grid p,.analysis-grid li{{font-size:13px}} details{{margin-top:16px;border-top:1px solid #e3dbd2;padding-top:12px}} summary{{cursor:pointer;font-weight:800;color:#8b2f1f}}
    .answer{{background:#f5f1eb;padding:12px;border-left:3px solid #a14632}} .need{{color:#a14632}} .search{{display:inline-block;margin-top:12px;color:#8b2f1f;font-weight:700;text-underline-offset:4px}}
    .notice{{margin-top:16px;padding:13px;border:1px solid #e4dbd1;background:#fff;color:#6d665f;font-size:13px;border-radius:10px}}
    @media(max-width:760px){{h1{{font-size:30px}}.stats,.grid,.analysis-grid{{grid-template-columns:1fr}}}}
  </style>
</head>
<body>
  <main>
    <header>
      <div class="eyebrow">NAVER BLOG KEYWORD BOARD</div>
      <h1>{escape(DASHBOARD_TITLE)}</h1>
      <p class="sub">네이버 상위 글의 공통점과 빈틈을 비교하고, AI가 인용하기 쉬운 원고 구조까지 준비합니다.</p>
      <div class="stats">
        <div class="stat"><b>{len(KEYWORDS)}</b><span>키워드 후보</span></div>
        <div class="stat"><b>{len(ANALYSIS)}</b><span>상세 분석 완료</span></div>
        <div class="stat"><b>{date.today().isoformat()}</b><span>확인 날짜</span></div>
      </div>
      <div class="notice">편집 평가와 AI 인용 준비 점수는 수강용 자체 기준입니다. 네이버 공식 점수나 실제 노출을 보장하지 않습니다.</div>
    </header>
    <section class="panel decision"><h2>오늘 먼저 쓸 글감 3개</h2>{top_html}</section>
    {section_html}
  </main>
</body>
</html>"""

output = Path("keyword_dashboard.html").resolve()
output.write_text(page, encoding="utf-8")
print(f"완성: {output}")
webbrowser.open(output.as_uri())

if OPEN_NAVER_SEARCH_TABS:
    for item in top_three:
        webbrowser.open(naver_url(item["keyword"]))
직접 만들기 어렵다면 프롬프트와 완성형 시작 코드를 함께 전달해 다시 시작하게 합니다.
19 / 19