Skill #2 · Ad copy generator

video-copywriter

AI-копирайтер агентства Performante. Пишет тексты, которые потом озвучивает ElevenLabs и которые становятся voiceover-скриптами для рекламных роликов. 7 типов текстов — от storytelling до адаптации конкретного конкурентного креатива.

Путь
~/.claude/skills/video-copywriter/
Триггеры
напиши текст для ролика, копирайтер, скрипт для видео, текст озвучки, voiceover script, ad copy, write script, сгенерируй текст, copywriter
Зависит от
Python 3.10+, SQLite, project.yaml → service_directions, brief.md, опц. competitor_refs таблица
Пэйрится с
voiceover (передаёт текст), orchestrator (вызывает в pipeline), analyzer (даёт transcriptions)

Что делает простыми словами

Это копирайтер, который знает 7 разных «форматов» рекламного текста. Юзер говорит «напиши текст про импланты в стиле storytelling» — а скилл:

  1. Читает project.yaml → понимает нишу, язык, направления услуг
  2. Читает brief.md → знает бизнес-контекст, ЦА, УТП
  3. Читает creatives/<direction>.md → видит лучшие тексты этого направления для референса
  4. Читает transcriptions из БД → знает что у клиента уже хорошо сработало
  5. Читает последние 10 текстов → чтобы не повторяться
  6. Пишет новый текст в выбранном из 7 типов
  7. Сохраняет в generated_texts с привязкой к проекту через project_texts

Дальше этот текст подхватывает voiceover и озвучивает.

Это не «генерация» в смысле API. Скилл не вызывает отдельную модель — он сам ЕСТЬ модель Claude. SKILL.md — это набор инструкций «как писать», который грузится в контекст. Сами тексты пишет Claude (то есть мы), а скрипты только сохраняют/читают.

Core принципы (что отличает текст, который конвертит)

Specifics over abstractions. «Lose 10 kg in a month» бьёт «lose weight fast». Числа, сроки, конкретные результаты создают доверие — потому что это falsifiable: читатель видит, что мы кладём конкретное на кон.
Value over selling. Веди с того, что зритель ПОЛУЧИТ, а не с того, что мы продаём. Люди хотят не продукт — они хотят transformation, которое он даёт.
Simple over complex. Короткие предложения. Простые слова. Если 15-летний не поймёт — переписывай. Озвучка играет на 1.2× — каждое лишнее слово = cognitive load.
Unique over templated. Никаких «В современном мире...» и «Задумывались ли вы?». Зритель видел сегодня уже тысячу таких роликов. Первые 3 секунды должны сломать паттерн.

7 типов текстов

1. STORYTELLING

Личный нарратив, который втягивает через общую боль и арку трансформации. Структура: hook с болью + hook to stay («досмотри до конца — расскажу как») → проблема ДО → discovery → как работает → results + social proof → CTA. От первого лица. Числа везде.

2. DIRECT OFFER

Максимальная компрессия. Формула: измеримый результат + срок + safety + CTA. Самый короткий формат. Каждое слово отрабатывает. Если цена — конкурентное преимущество или промо — лидируем ценой.

3. EXPERT VIDEO

Educational контент. Структура: viral hook (вопрос / триггер по deep pain) → expert-объяснение через бытовые аналогии → решение → CTA с оффером (если есть промо). Позиционирует бизнес как авторитета, потом мягко переходит к оферу.

4. TELEGRAM POST

Информационный/educational, НЕ direct selling. 500-1000 символов. Структура: интересный факт/инсайт → развитие темы (полезная инфа) → soft conclusion (можно вопрос аудитории, без жёсткого CTA). Строит экспертизу через контент. Можно bold и абзацы.

5. THREADS POST

Короткий, провокативный, на engagement. 100-280 символов. Структура: bold statement / неожиданный вопрос → краткое объяснение (1-2 фразы, опц.) → вопрос аудитории. Должен триггерить комментарии. Без явной рекламы.

6. TEXTOVER HOOK

Структурированный текст для анимированного оверлея на видео (без voiceover). Рендерится Remotion'ом. Видео 15 сек, каждый блок появляется поочерёдно с анимацией. Строгая структура из 4 блоков:

OFFER: Имплантация зубов за 1 день без боли
BULLET: • Гарантия 10 лет
BULLET: • Без разрезов и швов
BULLET: • Бесплатный КТ-снимок
PROFIT: Рассрочка 0% на 12 месяцев
CTA: Записаться на консультацию
БлокЛимитПравило
OFFER1 строка, 6-12 словHook, останавливающий скролл
BULLETSровно 3, по ≤5 словНЕ повторять слова из OFFER
PROFIT1 короткая строкаБонус/промо, НЕ дублирует OFFER/BULLETS
CTA2-5 словНЕ повторяет OFFER

Это не сценарий — это billboard copywriting. Каждый блок 2-4 сек на экране.

7. REFERENCE (адаптация конкурента)

Самая важная фича скилла. Адаптирует конкретный конкурентный креатив под нашего клиента. Использует таблицу competitor_refs, которая наполняется из tools/dentistry-research/ через npm run stage6.

Core rule: бери ОДИН конкретный креатив, не усредняй и не миксуй два. Сохраняй формат источника точно как есть — не пытайся «улучшить» в storytelling/expert/direct_offer. Match what the source is.

info_score (0..100) — приоритизация рефересов

Каждый импортированный креатив имеет info_score — это композитный показатель «насколько он informative + operationally heavy». Чем выше — тем больше у нас «мяса» для адаптации.

КомпонентWeightОткуда
длина transcript25analysis.transcript (озвучка видео — самое богатое)
длительность активности рекламы18creatives.total_active_time (proxy для ROI)
сколько креативов всего у клиники15derived из creatives table (proxy для marketing maturity)
длина body_text12creatives.body_text (FB caption)
variations (A/B count)9creatives.ads_count (сколько ротировались A/B)
currently active9creatives.is_active (крутится ли прямо сейчас)
длина OCR-текста8analysis.ocr_text (текст на картинке)
длина scene_description4analysis.scene_description
По дефолту фильтр --min-score 50 и ORDER BY score DESC. Stick to that:
  • ≥70 — rare (~1% всех импортов), top-tier от больших клиник с long-running active video
  • 50..69 — bulk usable refs
  • <50 — обычно короткие image-only креативы или untested one-offs. Bad raw material

Reference workflow (тип 7)

1. Определить направление

Юзер упомянул услугу («имплантация», «брекеты», etc.). Мапим на global slug (см. PROJECT_SLUG_TO_GLOBAL в db.py) или берём project slug напрямую.

2. Список кандидатов

python ~/.claude/skills/video-copywriter/scripts/db.py list-competitor-refs \
  <project-dir> \
  --direction implantation \
  --language ru \
  --limit 10 \
  --min-score 50

# → #142 [s73] [implantation] A/- BasDent / Алматы / ru / video | Верните зубы за один...
# → #98  [s64] [implantation] -/- White / Астана / ru / video | Болят зубы?...

Каждая строка: #<id> [s<score>] [direction] A/- <clinic> / <city> / <lang> / <media_type> | <preview>.... Если 0 результатов — дропнуть порог до 30, потом до 0; сказать юзеру.

3. Выбрать один

Либо юзер выбирает по ID, либо берём top-scored. Скажи, какой ref выбрал и почему (score + ещё одна причина — city match, similar service, strong hook).

4. Загрузить полный контент

python ~/.claude/skills/video-copywriter/scripts/db.py get-competitor-ref <project-dir> 142

# → JSON c полями: transcript, body_text, ocr_text, scene_description,
#    clinic_name, service_direction, headline, cta_type

5. Идентифицировать source text

Приоритет: transcript (озвучка — самое богатое) → body_text (FB caption) → ocr_text (текст на картинке). Это то, что адаптируем.

6. Адаптировать, сохраняя формат

СохранитьЗаменитьИзбегать
Структура, sentence rhythm, hook styleНазвание клиники → клиент (из brief)Литеральное копирование
Эмоциональная аркаЦены, услуги, сроки → клиентские данныеДобавление своих структурных элементов
Наличие/отсутствие CTA как в источникеГородМикс двух креативов
Длина/компактностьИмена врачей, отзывы → наши (или опустить)Push в сторону какого-то из 6 других типов

7. Сохранить с привязкой

python ~/.claude/skills/video-copywriter/scripts/db.py save-text <project-dir> \
  --type reference \
  --competitor-ref-id 142 \
  --text "<adapted text>" \
  --for-video

--competitor-ref-id сохраняет линк на источник — для будущего анализа «что мы у кого адаптировали».

Команды

Загрузить контекст проекта

python ~/.claude/skills/video-copywriter/scripts/db.py get-brief <project-dir>
python ~/.claude/skills/video-copywriter/scripts/db.py list-transcriptions <project-dir> --json
python ~/.claude/skills/video-copywriter/scripts/db.py list-texts <project-dir> --json --limit 10

Сохранить сгенерированный текст

python ~/.claude/skills/video-copywriter/scripts/db.py save-text <project-dir> \
  --type storytelling \
  --text "<текст>" \
  --for-video

--for-video — флаг «это voiceover-скрипт» (vs social post). По нему voiceover потом находит готовые к озвучке тексты.

Управление transcriptions (best-performing client creatives)

python ~/.claude/skills/video-copywriter/scripts/db.py add-transcription <project-dir> \
  --text "<транскрипт лучшего ролика клиента>" \
  --score 85

python ~/.claude/skills/video-copywriter/scripts/db.py list-transcriptions <project-dir> --json

Получить конкретный текст

python ~/.claude/skills/video-copywriter/scripts/db.py get-text <project-dir> <text-id>

Voiceover length guidelines

Тексты часто становятся voiceover-скриптами на 1.2× speed:

Target длительность видеоСлов (русский)Символов
15 секунд35-45200-300
30 секунд70-90400-600
45 секунд100-130600-900
60 секунд130-170900-1200

Это rough guides. Точную длительность даст voiceover после TTS.

Mandatory pre-flight: загрузить reference creatives

ВСЕГДА перед генерацией — прочитать project.yaml → service_directions, и для каждого direction открыть creative_ref файл. Пример:

service_directions:
  - slug: "implantation"
    name: "Имплантация зубов"
    creative_ref: "creatives/implantation.md"

Без этого скилл пишет «в пустоту» — без знания, какие тексты в нише уже отрабатывают.

Если запрашивается тип 7 (reference) — используем competitor_refs вместо creative_ref файлов. Если тип 1-6 — игнорируем competitor_refs, опираемся на brief + transcriptions + creative_ref.

Внутренности

Скрипты

ФайлЧто делает
scripts/db.pyCRUD по generated_texts, transcriptions, brief reader, competitor_refs list/get (project-scoped через junction)
scripts/schema.pySchema source-of-truth (v8) — копия одинакова во всех скиллах

Таблицы БД, которые трогает

ТаблицаДействиеЗачем
briefReadБизнес-контекст, ЦА, УТП
transcriptionsRead / INSERTЛучшие тексты клиента — для тона/стиля
generated_textsINSERT / ReadВсе генерации (новые и для проверки «не повторяться»)
project_textsINSERTJunction: scope текста к проекту
competitor_refsReadИмпортированные конкурентные креативы (для type 7)

Конфиг из project.yaml

language: "ru"                    # язык генерации
niche: "Стоматология"             # для контекста
service_directions:               # обязательно для пред-загрузки
  - slug: "implantation"
    name: "Имплантация зубов"
    creative_ref: "creatives/implantation.md"
  - slug: "checkup"
    name: "Чекап полости рта"
    creative_ref: "creatives/checkup.md"

Gotchas и tips

Не игнорируй creative_ref файлы. Это основной источник «как клиент говорит» — там лежат тексты, которые юзер сам или его маркетолог посчитали удачными. Генерация без них = generic ad copy.
Не повторяйся. Перед генерацией обязательно list-texts --limit 10. Если последние 3 текста были storytelling — переключайся. Если все три были про «гарантию 10 лет» — найди другой angle.
В type 7 (reference) НЕ микшировать два креатива. Один источник = один адаптированный текст. Если хочется два — два отдельных вызова. Иначе получается «франкенштейн», у которого ритм рваный и hook не работает.
Output ТОЛЬКО финальный текст. Никаких «Here's the text:» заголовков, никаких explanations, никаких quotes-wrappers. Текст идёт прямо в TTS — лишние символы будут озвучены.
textover_hook ≠ voiceover script. Они разные пайплайны. textover_hook идёт в Remotion для overlay, voiceover-типы (storytelling/direct_offer/expert_video) идут в ElevenLabs. Флаг --type textover_hook + --for-video = именно textover-pipeline.
info_score override. Если юзер явно просит топ-топ — подними до --min-score 70. Если в нише по 50+ пусто — дропни до 30, потом до 0, и скажи юзеру что сделал и почему.

Место в пайплайне

orchestrator copywriter voiceover director captions

Copywriter = первое звено генерации. Без него не существует, что озвучивать. Опирается на материалы из analyzer (transcriptions) и project setup (creative_ref файлы).

Источники контекста: brief.md (бизнес), creatives/*.md (примеры от клиента), transcriptions table (transcripts его лучших роликов), competitor_refs table (только для type 7). Выход: запись в generated_texts с привязкой через project_texts.