---
title: "MediaConductor"
description: "Доменний фасад для сценарного медіа, Audible у документації (TTS радіоведучого), Visual walkthroughs, Markdown-близнюк і Agent NODUS — збагачення за SHA з фоновою генерацією під час першого завантаження"
locale: "uk"
---
# MediaConductor

MediaConductor — це **доменний фасад** Ring Platform для багатокрокової генерації медіа. Він не перевинаходить провайдерів, а компілює промпти й делегує роботу `VideoConductor`, `ImageConductor`, `AudioConductor` і `TextConductor`. Найпомітніша поверхня — **медіа статей документації**: кожна сторінка документації може запропонувати **Audible** (озвучення TTS у стилі радіоведучого), **Visual** (необов’язкове відео walkthrough для учасника+), **Markdown** (прозовий близнюк `.md`) і **Agent** (мінімізований NODUS за адресою `/docs/.../nodus.json`). `/llms.txt` індексує спочатку `.md`-близнюків; NODUS — структурована вторинна поверхня.

> **Info**
> Використовуйте вкладки **Founder** / **Developer** на бічній панелі документації, щоб відфільтрувати цю сторінку. Засновники бачать кнопки в заголовку статті та керування витратами; розробники — модулі збагачення, контракти SHA-кешу, фонову роботу `after()` і перевірені маршрути.

## Що це забезпечує

| Поверхня | Вхід | Результат |
|---------|-------|--------|
| Docs Audible | Заголовок **Audible** → `generateDocNarration` → `ensureTtsAudio` | `audible-text` у стилі радіоведучого → TTS (`tts-audio`), публічний, кешується за SHA |
| Docs Visual | Заголовок **Visual** → `generateDocWalkthrough` | Підсумковий TTS + необов’язкове чернеткове відео (відео = member+) |
| Docs Markdown | Заголовок **Markdown** → `/docs/.../*.md` | Прозовий близнюк для агентів (`Accept: text/markdown` або суфікс `.md`) |
| Docs Agent | Заголовок **Create** / **Agent** → `ensureLlmText` | Мінімізований NODUS `docs_article` (`llm-text`) + буфер обміну |
| Індекс Agent | `/llms.txt` | Керований Markdown-індекс; основні посилання — `.md`-близнюки; `/nodus.json` названо як структурований супутник |
| Фонове збагачення | RSC `after(ensureDocsArticleEnrichmentBackground)` | Audible + Agent прогріваються під час першого завантаження статті, якщо відсутні. **Visual залишається on-demand** (ніколи не в `after()`) |
| Сценарне медіа | `MediaConductor.generateScript` / `generateClip` | Відео кожного кліпу з `ScriptedVideoGenerationRequest` |

### For founders

## Чому це важливо для вашого клону

- **Документація, що говорить** — кнопка **Audible** у заголовку статті відтворює теплий сценарій радіоведучого (холодний вступ, суть, підводні камені, наступний крок), а не роботизований переказ кожного заголовка й таблиці. Натисніть **Show transcript** поруч із плеєром, коли потрібен текст озвучення.
- **Заплатіть один раз, використовуйте назавжди** — перша генерація зберігає `audible-text` і MP3 із ключем повного SHA-256 вмісту. Наступні відвідування повторно використовують файл. Редагування MDX змінює SHA, тому озвучення генерується знову (з align-проходом, який вплітає нові факти в попередній сценарій).
- **Готово, поки ви читаєте** — під час першого відкриття сервер планує фонове збагачення. Кнопки показують **Generating…**, а клієнт опитує стан кожні 2 с, доки Audible та Agent не будуть готові.
- **Зручно для агентів** — `/llms.txt` перелічує документацію з основними посиланнями `.md`; кожна сторінка також відкриває `/nodus.json`. Кнопка **Markdown** копіює URL близнюка. **Create** будує payload один раз; **Agent** (+ копіювання) копіює JSON або абсолютний URL NODUS, коли він готовий.
- **Контрольовані витрати Visual** — Audible публічний; відео **Visual** потребує авторизованої ролі **member+**, тому великі витрати на відео залишаються обмеженими.
- **Єдиний мозок медіа** — той самий conductor керує сценарними маркетинговими кліпами та walkthrough документації через налаштованих провайдерів image / video / audio / text.

  
- **[Wallet](/docs/features/wallet.md)** — Ролі учасника, які відкривають Visual-відео walkthrough.

  
- **[VideoConductor](/docs/features/video-conductor.md)** — Двигун сценарного відео, якому делегує MediaConductor.

  
- **[News](/docs/features/news.md)** — NewsConductor — споріднений фасад для збагачення медіа статей.

> **Tip**
> Подивіться у правий верхній кут будь-якої статті документації: **Audible** · **Visual** · **Markdown** · **Create** / **Agent**. Якщо ви щойно відкрили сторінку вперше, дочекайтеся завершення Generating… — після цього Play звертатиметься до кешу. Visual генерується лише за кліком і не прогрівається у фоні.

### For developers

## Архітектура

`lib/media/conductor/media-conductor.ts` експортує об’єкт `MediaConductor`. Docs **Audible** / **Agent** надають перевагу SSOT збагачення в `lib/docs/docs-article-enrichment.ts` (TextConductor у стилі радіоведучого → AudioConductor TTS → Filebase). Walkthrough **Visual** і далі проходить через `MediaConductor.generateDocWalkthrough` і дзеркалиться в `generated_docs_media`.

### Модулі

| Модуль | Шлях | Роль |
|--------|------|------|
| MediaConductor | `lib/media/conductor/media-conductor.ts` | `generateClip`, `generateScript`, `generateDocWalkthrough` |
| SSOT збагачення docs | `lib/docs/docs-article-enrichment.ts` | `ensureAudibleText`, `ensureTtsAudio`, `ensureLlmText`, `getDocsArticleMediaStatus`, `ensureDocsArticleEnrichmentBackground` |
| Дії медіа docs | `app/_actions/docs-media.ts` | `getDocMediaStatus`, `ensureDocMediaBackground`, `generateDocNarration`, `createOrGetDocAgentNodus`, `generateDocWalkthrough` |
| Chrome статті | `components/docs/docs-article-shell.tsx` | Завантажує стан; `after()` планує Audible + Agent, коли `shouldEnrich` (не Visual) |
| Кнопки заголовка | `components/docs/docs-article-media-actions.tsx` | UI Audible / Visual / Markdown / Agent; опитування кожні 2 с під час генерації |
| Дзеркало застарілого URL | `lib/docs/docs-media-cache.ts` | Рядки `generated_docs_media` (коротке hash-дзеркало URL walkthrough / narration) |
| API Agent NODUS | `app/api/docs/nodus/[locale]/[[...slug]]/route.ts` | Публічний JSON через rewrite у `next.config.mjs` |
| API Markdown-близнюк | `app/api/docs/markdown/[locale]/[[...slug]]/route.ts` | Публічний `.md` через rewrite `/docs/:path*.md` у `next.config.mjs` |
| Індекс LLM | `app/llms.txt/route.ts` | Керований індекс `/llms.txt` — основні посилання `.md` |
| Схема | `data/migrations/045_docs_media_and_enrichment.sql` | `generated_docs_media` + `docs_article_enrichment` (застосовано local + prod) |
| Делегати | `lib/video`, `lib/images`, `lib/audio`, `lib/text` | Video / Image / Audio / Text conductors |

### Потік медіа docs

```mermaid
sequenceDiagram
  participant Shell as docs-article-shell RSC
  participant After as Next.js after()
  participant UI as DocsArticleMediaActions
  participant SA as docs-media actions
  participant EN as docs-article-enrichment
  participant TC as TextConductor
  participant AC as AudioConductor
  participant DB as docs_article_enrichment

  Shell->>EN: getDocsArticleMediaStatus
  alt shouldEnrich
    Shell->>After: ensureDocsArticleEnrichmentBackground
    After->>EN: ensureTtsAudio then ensureLlmText
  end
  UI->>SA: poll getDocMediaStatus every 2s
  SA->>EN: status snapshot
  Note over UI: Audible click if still missing
  UI->>SA: generateDocNarration
  SA->>EN: ensureTtsAudio
  EN->>TC: radio-host or ALIGN_EXISTING_AUDIBLE
  TC-->>EN: audibleText
  EN->>AC: synthesize objectKey docs/sha256.mp3
  AC-->>EN: audioUrl
  EN->>DB: save enrichment + invalidate history
  SA-->>UI: audioUrl + status
```

### Контракт SHA-256-кешу

- **Колекції:** `docs_article_enrichment` (`audible-text` / `tts-audio` / `llm-text` + `history`) і `generated_docs_media` (дзеркало URL narration/walkthrough) через `db()` — зареєстровані в `BackendSelector` + `PostgreSQLAdapter`.
- **Content SHA:** `hashArticleContentSha256(locale, slug, plain)` = повний `sha256(\`${locale}:${slug.join('/')}:${plain}\`)`. Стан Ready вимагає збігу `contentSha256` у enrichment + `ttsAudio.contentSha256`.
- **ID рядка:** `docs-enrich-{locale}-{sha256(slug).slice(0,24)}` (стабільний для locale/slug; content SHA зберігається в тілі документа).
- **TTS objectKey:** `{AUDIO_STORAGE_PREFIX||generated/audio}/docs/{fullSha256}.mp3` — повторне використання лише коли URL, objectKey і SHA збігаються; інакше генерація повторюється.
- **Зміна SHA:** попередні `ttsAudio` / `audibleText` / `llmText` переміщуються в `history.audibles` / `history.llmTexts` зі `status: 'invalidated'`. Нове audible використовує TextConductor `TASK_MODE: ALIGN_EXISTING_AUDIBLE`, коли існує попередній сценарій.
- **Шлях Agent:** `ensureLlmText` будує мінімізований NODUS (`object_type: docs_article`, `source_content_hash`). Публічні URL: `/docs//nodus.json` і `/:locale/docs/.../nodus.json` → rewrite → API route.
- **Індекс:** `GET /llms.txt` перелічує абсолютні посилання `.md`-близнюків (сканування DEFAULT_LOCALE). Заголовок файлу також документує `/nodus.json` як структурований супутник (`object_type: docs_article`).

### UX заголовка статті (перевірено)

| Керування | Відсутнє | Генерується | Готове |
|---------|---------|------------|-------|
| **Audible** | Запускає `generateDocNarration` | Підпис зі spinner | Відтворює `[data-docs-audible-player]`; необов’язковий показ/приховування транскрипту |
| **Visual** | `generateDocWalkthrough({ enableVideo: true })` | Spinner | Показує відео, коли воно повернулося; доступно member+; ніколи не auto-warm |
| **Markdown** | Копіює `/docs/.md` | — | Миттєво; без генерації |
| **Agent** | Підпис **Create** (`agentCreate`) → `createOrGetDocAgentNodus`, потім буфер обміну | Spinner | Підпис **Agent** + іконка копіювання — копіює NODUS JSON або абсолютний URL |

Клієнтський fallback: якщо `shouldEnrich`, а RSC `after()` не завершився, `ensureDocMediaBackground` запускається з клієнта; інтервал опитування — **2000 мс**.

### Правила доступу (перевірено)

**Audible публічний**

`generateDocNarration` не має auth-gate — будь-який відвідувач може його запустити; витрати амортизуються через SHA-кеш / фонове збагачення.

**Visual-відео потребує member+**

У `generateDocWalkthrough` параметр `enableVideo: true` потребує сесії (`AUTH_REQUIRED`) і `hasMemberPrivileges(session.user.role)` (`MEMBER_REQUIRED`). Walkthrough лише з аудіо не має рольового обмеження.

**Якість чернетки для docs-відео**

`MediaConductor.generateDocWalkthrough` запитує `qualityMode: 'draft'`, `aspectRatio: '16:9'`, `purpose: 'docs-walkthrough'` і зберігає результат у Filebase.

### Сімейство conductor-ів

MediaConductor — один із кількох тонких доменних фасадів, які повторно використовують спільні media conductors, не дублюючи логіку провайдерів:

| Conductor | Шлях | Роль |
|-----------|------|------|
| MediaConductor | `lib/media/conductor/media-conductor.ts` | Сценарні кліпи + walkthrough документації |
| NewsConductor | `features/news/conductor/news-conductor.ts` | Генерація статей, переклад, збагачення медіа під час публікації (TL;DR + TTS + featured image) |
| WalletConductor | `features/wallet/conductor/wallet-conductor.ts` | Фасад багатокрокових операцій wallet поверх server actions wallet |

## Пов’язана документація

- [features/doc-system](/docs/features/doc-system.md) — Передумова: MDX chrome документації та бічна панель із добором аудиторії, де розміщено заголовок Audible / Visual / Markdown / Agent.

- [features/video-conductor](/docs/features/video-conductor.md) — Залежність: VideoConductor — двигун чернеткових walkthrough, який MediaConductor викликає для Visual.

- [features/generative-media](/docs/features/generative-media.md) — Див. також: Generative Gallery Upload | Generate — споріднена медіа-поверхня, не walkthrough документації.

- [features/news](/docs/features/news.md) — Той самий процес: NewsConductor збагачує новинні статті TTS та зображеннями, використовуючи те саме сімейство conductor-ів.

- [features/wallet](/docs/features/wallet.md) — Наступний крок: ролі учасника, які відкривають генерацію Visual-відео.

- [development/scripted-media-pipeline](/docs/development/scripted-media-pipeline.md) — Поглиблення: сценарний pipeline кліпів за MediaConductor.generateScript / generateClip.

1 year)"
  description="Недійсні audibles і llm-text зберігаються в docs_article_enrichment.history (і об’єктах Filebase). Потрібно додати collector, який збирає недійсні рядки history та об’єкти ring-filebase, старші за 1 рік — TODO(gc) у docs-article-enrichment.ts."
  implementationCost={28}
  labels={['docs', 'media', 'ops', 'storage']}
/>
