Fix podcasts generating in English + failing with invalid JSON
Two root causes, both fixed in the bind-mounted podcast prompt templates
(prompts/podcast/*.jinja):
1. Language: the episode profile's `language` field IS passed to both
podcast_creator templates as {{ language }}, but the stock templates never
reference it — so podcasts came out English (driven only by the English
stock briefings/speakers), then read aloud by the German-locked Chatterbox
TTS = "English with a German accent". Added a CRITICAL LANGUAGE REQUIREMENT
block keyed on {{ language }} to both templates; now `language: "de"`
actually forces German. Verified end-to-end: a full run produced a 44-line
all-German transcript + audio.
2. Invalid json output failures: qwen3.5:27b is a thinking model; on long
segments the <think> block ate the response-token budget and truncated the
JSON. Prepended /no_think to both templates (~3x faster, valid JSON).
Templates are bind-mounted read-only via docker-compose (directory mount, so
edits survive a container restart without inode-staleness). Bundled briefings
and speaker backstories were also translated to German to reduce drift.
Known limitation documented: feeding an entire book (~70k tokens) as podcast
content makes each of the 6 LLM calls take ~3.5 min and is unreliable; use a
shorter source or summary. Confirmed working with concise content.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
e2fb113213
commit
054f867a8a
6 changed files with 304 additions and 18 deletions
|
|
@ -379,21 +379,36 @@ Das Episode- oder Sprecherprofil verweist auf ein Modell ohne konfiguriertes Cre
|
||||||
`PUT /api/speaker-profiles/{id}` (`voice_model`) auf registrierte lokale/OpenRouter-Modelle
|
`PUT /api/speaker-profiles/{id}` (`voice_model`) auf registrierte lokale/OpenRouter-Modelle
|
||||||
umstellen — siehe `scripts/setup_models.sh` für die IDs der Standardmodelle.
|
umstellen — siehe `scripts/setup_models.sh` für die IDs der Standardmodelle.
|
||||||
|
|
||||||
### Podcast wird auf Englisch statt Deutsch erzeugt
|
### Podcast wird auf Englisch statt Deutsch erzeugt (oder auf Englisch mit deutschem Akzent vorgelesen)
|
||||||
|
|
||||||
Das verwendete Episode-Profil hat kein `language`-Feld gesetzt — ohne Angabe generiert das
|
Das ist behoben: Die Podcast-Prompt-Vorlagen (`prompts/podcast/outline.jinja` und
|
||||||
Sprachmodell standardmäßig auf Englisch, unabhängig von der Sprache der Quelle. Prüfen und
|
`transcript.jinja` in diesem Projekt) wurden um eine explizite Sprachanweisung ergänzt, die das
|
||||||
korrigieren:
|
`language`-Feld des Episode-Profils auswertet — sie werden per Bind-Mount aus `docker-compose.yml`
|
||||||
|
in den Container eingehängt. Setzt du am Episode-Profil `language: "de"`, kommt der Podcast auf
|
||||||
|
Deutsch. (Vorher hatte das `language`-Feld keine Wirkung, weil die mitgelieferten Vorlagen es
|
||||||
|
ignorierten — daher englischer Text, der von der deutsch-fixierten TTS mit Akzent vorgelesen wurde.)
|
||||||
|
|
||||||
|
Falls doch wieder Englisch erscheint, prüfe das `language`-Feld:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s http://127.0.0.1:5055/api/episode-profiles | python3 -c \
|
curl -s http://127.0.0.1:5055/api/episode-profiles | python3 -c \
|
||||||
"import json,sys; [print(p['name'], p['language']) for p in json.load(sys.stdin)]"
|
"import json,sys; [print(p['name'], p['language']) for p in json.load(sys.stdin)]"
|
||||||
```
|
```
|
||||||
|
|
||||||
Fehlt `de`, per `PUT /api/episode-profiles/{id}` (vollständiger Body nötig, siehe oben)
|
Fehlt `de`/`de-DE`, per `PUT /api/episode-profiles/{id}` (vollständiger Body) ergänzen. Zusätzlich
|
||||||
`"language": "de"` ergänzen. Die drei mitgelieferten Profile (`business_analysis`,
|
sind Briefing und Sprecherbeschreibungen der mitgelieferten Profile auf Deutsch übersetzt (hilft
|
||||||
`solo_expert`, `tech_discussion`) sind bereits korrigiert; bei neu angelegten eigenen Profilen
|
gegen Sprach-Drift, wenn der Quellinhalt englisch ist). **Wichtig:** Änderst du die
|
||||||
selbst daran denken.
|
Vorlagen-Dateien selbst, ist danach ein Container-Neustart nötig (`docker compose up -d
|
||||||
|
--force-recreate open_notebook`), damit der Bind-Mount die neue Version übernimmt.
|
||||||
|
|
||||||
|
### Podcast-Erzeugung schlägt mit „Invalid json output" fehl
|
||||||
|
|
||||||
|
Das Textmodell hat ungültiges JSON geliefert — passierte bei `qwen3.5:27b` (einem „denkenden"
|
||||||
|
Modell), wenn der gesamte Notebook-Inhalt (bei einem ganzen Buch ~70.000 Tokens) in jeden
|
||||||
|
Transkript-Abschnitt gepackt wird: Der Denk-Block frisst dann das Antwort-Budget auf und das JSON
|
||||||
|
wird abgeschnitten. Behoben durch `/no_think` als erste Zeile beider Podcast-Vorlagen (schaltet
|
||||||
|
den Denkmodus ab, ~3× schneller, volles Budget fürs JSON). Falls es dennoch auftritt: kürzeren
|
||||||
|
Quellinhalt verwenden (nicht das ganze Buch) oder die Generierung erneut starten.
|
||||||
|
|
||||||
### Weitere technische Details
|
### Weitere technische Details
|
||||||
|
|
||||||
|
|
|
||||||
39
CLAUDE.md
39
CLAUDE.md
|
|
@ -41,13 +41,38 @@ A separate local `llama.cpp` server exists on this machine (managed via `~/llama
|
||||||
|
|
||||||
**Chat model context window:** the Ollama credential used for `qwen3.5:27b` (`credential:di8b31l16zikyyb6isyi`) has `num_ctx=98304` set explicitly. Without this, esperanto's `OllamaLanguageModel` silently defaults `num_ctx` to **8192** regardless of the model's real capability or `OLLAMA_CONTEXT_LENGTH` — any chat context (e.g. "full content" mode on a real document) beyond that gets truncated by Ollama, and because `qwen3.5:27b` is a thinking model, the truncated prompt frequently produces an empty final answer (the response is silently swallowed by `clean_thinking_content`) instead of a visible error — looks exactly like "chat gives no answer" from the UI. `98304` is the largest value that still keeps the whole model on GPU 1 (`ollama ps` shows `100% GPU`); `131072` spills ~91% onto CPU and makes a single response take 5-6 minutes instead of ~1-2. Even at 98304, a full-book "Volltext" chat (~70k+ tokens of context) takes ~2-3 minutes — that's inherent to processing that much context on one consumer GPU, not a bug. For large documents, the default short/RAG context mode (only relevant chunks, not the whole document) stays fast; reserve "Volltext" for shorter sources. If `qwen3.5:27b` ever gets swapped for a different Ollama chat model, re-check this credential's `num_ctx` still makes sense for its VRAM footprint.
|
**Chat model context window:** the Ollama credential used for `qwen3.5:27b` (`credential:di8b31l16zikyyb6isyi`) has `num_ctx=98304` set explicitly. Without this, esperanto's `OllamaLanguageModel` silently defaults `num_ctx` to **8192** regardless of the model's real capability or `OLLAMA_CONTEXT_LENGTH` — any chat context (e.g. "full content" mode on a real document) beyond that gets truncated by Ollama, and because `qwen3.5:27b` is a thinking model, the truncated prompt frequently produces an empty final answer (the response is silently swallowed by `clean_thinking_content`) instead of a visible error — looks exactly like "chat gives no answer" from the UI. `98304` is the largest value that still keeps the whole model on GPU 1 (`ollama ps` shows `100% GPU`); `131072` spills ~91% onto CPU and makes a single response take 5-6 minutes instead of ~1-2. Even at 98304, a full-book "Volltext" chat (~70k+ tokens of context) takes ~2-3 minutes — that's inherent to processing that much context on one consumer GPU, not a bug. For large documents, the default short/RAG context mode (only relevant chunks, not the whole document) stays fast; reserve "Volltext" for shorter sources. If `qwen3.5:27b` ever gets swapped for a different Ollama chat model, re-check this credential's `num_ctx` still makes sense for its VRAM footprint.
|
||||||
|
|
||||||
**Podcast language:** the three bundled episode profiles (`business_analysis`, `solo_expert`,
|
**Podcast language + reliability — fixed via patched prompt templates (`prompts/podcast/`,
|
||||||
`tech_discussion`) ship with `language: null`, which the underlying `podcast_creator` library
|
bind-mounted).** Two separate problems, one fix location:
|
||||||
treats as "no language specified" and defaults to English for both outline and transcript
|
|
||||||
generation — regardless of what language the source content or the briefing text is in. All
|
1. *Language.* The episode profile's `language` field (`"de"` → resolved to `"German"`) **is**
|
||||||
three are set to `language: "de"` here. If you create a new episode profile, set `language`
|
passed into both `podcast_creator` prompt templates as a `{{ language }}` variable
|
||||||
explicitly (`PUT /api/episode-profiles/{id}`, full body) — it doesn't inherit from the notebook
|
(`nodes.py`, both `generate_outline_node` and `generate_transcript_node`), but the stock
|
||||||
or the source.
|
templates shipped in the image never reference it — so setting `language` had no effect and
|
||||||
|
podcasts came out in English (the stock briefings and speaker backstories are English, which
|
||||||
|
is the only language signal the model then sees). English text read aloud by the German-locked
|
||||||
|
Chatterbox TTS is what produced the "English with a bad German accent" symptom.
|
||||||
|
2. *Reliability.* `qwen3.5:27b` is a thinking model. Podcast content is the **entire notebook**
|
||||||
|
(`Notebook.get_context()` → every source's full text + all insights; for a whole book that's
|
||||||
|
~70k+ tokens), fed into *each* transcript-segment call. On long segments the `<think>` block
|
||||||
|
eats the 5000-token response budget and the JSON gets truncated → `Invalid json output` →
|
||||||
|
whole job fails. (Confirmed: `/no_think` cut a segment from 98s to 34s and left valid JSON.)
|
||||||
|
|
||||||
|
Fix — both handled in the two templates under `prompts/podcast/`, bind-mounted read-only over
|
||||||
|
the image's copies via `docker-compose.yml`:
|
||||||
|
- Prepended `/no_think` as the first line of both templates (Qwen honors it anywhere; harmless
|
||||||
|
text for non-Qwen models) — disables thinking, freeing the token budget and ~3x speedup.
|
||||||
|
- Added a `{% if language %}CRITICAL LANGUAGE REQUIREMENT … in {{ language }}{% endif %}` block
|
||||||
|
near the end of both templates, so the already-plumbed `language` field now actually forces the
|
||||||
|
output language.
|
||||||
|
|
||||||
|
The bundled briefings and speaker backstory/personality were **also** translated to German (belt
|
||||||
|
and suspenders; reduces English drift from the source content), but the template change is what
|
||||||
|
makes `language` authoritative. **Editing these templates requires a container restart** to take
|
||||||
|
effect — they're bind-mounted, and the mount is the directory `prompts/podcast/` (not individual
|
||||||
|
files, which go stale on inode-replacing edits). If you switch off `qwen3.5:27b`, the `/no_think`
|
||||||
|
line becomes inert but harmless.
|
||||||
|
|
||||||
|
If you create your own episode profile, just set `language` — the template handles the rest.
|
||||||
|
|
||||||
### Text-to-speech / speech-to-text
|
### Text-to-speech / speech-to-text
|
||||||
|
|
||||||
|
|
|
||||||
11
README.md
11
README.md
|
|
@ -204,6 +204,11 @@ Kurzreferenz — Details jeweils in [`CLAUDE.md`](CLAUDE.md):
|
||||||
leere Chat-Antworten bei größerem Kontext, ohne sichtbaren Fehler.
|
leere Chat-Antworten bei größerem Kontext, ohne sichtbaren Fehler.
|
||||||
- **Neue Host-Ports brauchen eine `ufw`-Regel**, sonst kann der Container sie nicht erreichen
|
- **Neue Host-Ports brauchen eine `ufw`-Regel**, sonst kann der Container sie nicht erreichen
|
||||||
(Timeout, keine Fehlermeldung in Open Notebook selbst).
|
(Timeout, keine Fehlermeldung in Open Notebook selbst).
|
||||||
- **Podcasts werden ohne explizites `language`-Feld auf Englisch erzeugt**, unabhängig von der
|
- **Podcast-Sprache** wird über das `language`-Feld des Episode-Profils gesteuert, aber nur
|
||||||
Sprache der Quelle. Die drei mitgelieferten Episode-Profile sind bereits auf `"de"` gesetzt;
|
dank der gepatchten Prompt-Vorlagen unter `prompts/podcast/` (per Bind-Mount in
|
||||||
bei selbst angelegten Profilen selbst daran denken.
|
`docker-compose.yml` eingehängt) — die Original-Vorlagen im Image ignorieren `language`, was
|
||||||
|
englische Podcasts (von der deutsch-fixierten TTS mit Akzent vorgelesen) verursachte. Die
|
||||||
|
Vorlagen enthalten zusätzlich `/no_think`, damit `qwen3.5:27b` bei langem Quellinhalt nicht
|
||||||
|
durch überlange Reasoning-Blöcke ungültiges JSON liefert. Änderst du die Vorlagen, danach
|
||||||
|
`docker compose up -d --force-recreate open_notebook`. Details:
|
||||||
|
[`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md#10-troubleshooting) und [`CLAUDE.md`](CLAUDE.md).
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,11 @@ services:
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
- ./notebook_data:/app/data
|
- ./notebook_data:/app/data
|
||||||
|
# Podcast-Prompt-Vorlagen mit expliziter Sprachanweisung ({{ language }})
|
||||||
|
# und abgeschaltetem Thinking-Modus (/no_think), damit Podcasts in der
|
||||||
|
# eingestellten Sprache erzeugt werden (statt Englisch) und das JSON bei
|
||||||
|
# langen Segmenten nicht durch riesige Reasoning-Blöcke abgeschnitten wird.
|
||||||
|
# Verzeichnis-Mount (nicht Einzeldateien), damit Edits ohne Inode-Probleme
|
||||||
|
# nach einem Container-Neustart greifen. Der Ordner im Image enthält nur
|
||||||
|
# genau diese zwei Vorlagen.
|
||||||
|
- ./prompts/podcast:/app/prompts/podcast:ro
|
||||||
|
|
|
||||||
91
prompts/podcast/outline.jinja
Normal file
91
prompts/podcast/outline.jinja
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/no_think
|
||||||
|
You are an AI assistant specialized in creating podcast outlines. Your task is to create a detailed outline for a podcast episode based on a provided briefing. The outline you create will be used to generate the podcast transcript.
|
||||||
|
|
||||||
|
Here is the briefing for the podcast episode:
|
||||||
|
<briefing>
|
||||||
|
{{ briefing }}
|
||||||
|
</briefing>
|
||||||
|
|
||||||
|
The user has provided content to be used as the context for this podcast episode:
|
||||||
|
<context>
|
||||||
|
{% if context is string %}
|
||||||
|
{{ context }}
|
||||||
|
{% else %}
|
||||||
|
{% for item in context %}
|
||||||
|
<content_piece>
|
||||||
|
{{ item }}
|
||||||
|
</content_piece>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</context>
|
||||||
|
|
||||||
|
The podcast will feature the following speakers:
|
||||||
|
<speakers>
|
||||||
|
{% for speaker in speakers %}
|
||||||
|
- **{{ speaker.name }}**: {{ speaker.backstory }}
|
||||||
|
Personality: {{ speaker.personality }}
|
||||||
|
{% endfor %}
|
||||||
|
</speakers>
|
||||||
|
|
||||||
|
Please create an outline based on this briefing. Your outline should consist of {{ num_segments }} main segments for the podcast episode, along with a description of each segment. Follow these guidelines:
|
||||||
|
|
||||||
|
1. Read the briefing carefully and identify the main topics and themes.
|
||||||
|
2. Create {{ num_segments }} distinct segments that cover the entire scope of the briefing.
|
||||||
|
3. For each segment, provide a clear and concise name that reflects its content.
|
||||||
|
4. Write a detailed description for each segment, explaining what will be discussed and provide suggestions of topics according to the context given. The writer will use your suggestion to design the dialogs.
|
||||||
|
5. Consider the speaker personalities and backstories when planning segments - match content to speaker expertise.
|
||||||
|
6. Ensure that the segments flow logically from one to the next.
|
||||||
|
7. This is a whole podcast so no need to reintroduce speakers or topics on each segment. Segments are just markers for us to know to change the topics, nothing else.
|
||||||
|
8. Include an introduction segment at the beginning and a conclusion or wrap-up segment at the end.
|
||||||
|
|
||||||
|
Format your outline using the following structure:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"name": "[Segment Name]",
|
||||||
|
"description": "[Description of the segment content]",
|
||||||
|
"size": "short"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[Segment Name]",
|
||||||
|
"description": "[Description of the segment content]",
|
||||||
|
"size": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[Segment Name]",
|
||||||
|
"description": "[Description of the segment content]",
|
||||||
|
"size": "long"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Formatting instructions:
|
||||||
|
{{ format_instructions}}
|
||||||
|
|
||||||
|
Additional tips:
|
||||||
|
- Make sure the segment names are catchy and informative.
|
||||||
|
- In the descriptions, include key points or questions that will be addressed in each segment.
|
||||||
|
- Consider the target audience mentioned in the briefing when crafting your outline.
|
||||||
|
- If the briefing mentions a guest, include segments for introducing the guest and featuring their expertise.
|
||||||
|
- The size of the segment should be short, medium or long. Think about the content of the segment and how important it is to the episode.
|
||||||
|
|
||||||
|
{% if language %}
|
||||||
|
CRITICAL LANGUAGE REQUIREMENT:
|
||||||
|
- Write the ENTIRE outline — every segment name and every segment description — exclusively in {{ language }}.
|
||||||
|
- Do NOT use English or any other language, not even for technical terms or proper concepts where a {{ language }} wording exists.
|
||||||
|
- These instructions are written in English, but your output MUST be in {{ language }}.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
IMPORTANT OUTPUT FORMAT:
|
||||||
|
- If you use extended thinking with <think> tags, put ALL your reasoning inside <think></think> tags
|
||||||
|
- Put the final JSON output OUTSIDE and AFTER any <think> tags
|
||||||
|
- Do NOT wrap the JSON in ```json code blocks - return the raw JSON object only
|
||||||
|
- Example correct format:
|
||||||
|
<think>Let me analyze the briefing...</think>
|
||||||
|
{"segments": [...]}
|
||||||
|
|
||||||
|
Please provide your outline now, following the format and guidelines provided above.
|
||||||
142
prompts/podcast/transcript.jinja
Normal file
142
prompts/podcast/transcript.jinja
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
/no_think
|
||||||
|
You are an AI assistant specialized in creating podcast transcripts.
|
||||||
|
Your task is to generate a transcript for a specific segment of a podcast episode based on a provided briefing and outline.
|
||||||
|
The transcript will be used to generate podcast audio. Follow these instructions carefully:
|
||||||
|
|
||||||
|
First, review the briefing for the podcast episode:
|
||||||
|
<briefing>
|
||||||
|
{{ briefing }}
|
||||||
|
</briefing>
|
||||||
|
|
||||||
|
The user has provided content to be used as the context for this podcast episode:
|
||||||
|
<context>
|
||||||
|
{% if context is string %}
|
||||||
|
{{ context }}
|
||||||
|
{% else %}
|
||||||
|
{% for item in context %}
|
||||||
|
<content_piece>
|
||||||
|
{{ item }}
|
||||||
|
</content_piece>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</context>
|
||||||
|
|
||||||
|
The podcast features the following speakers:
|
||||||
|
<speakers>
|
||||||
|
{% for speaker in speakers %}
|
||||||
|
- **{{ speaker.name }}**: {{ speaker.backstory }}
|
||||||
|
Personality: {{ speaker.personality }}
|
||||||
|
{% endfor %}
|
||||||
|
</speakers>
|
||||||
|
|
||||||
|
Next, examine the outline produced by our director:
|
||||||
|
<outline>
|
||||||
|
{{ outline }}
|
||||||
|
</outline>
|
||||||
|
|
||||||
|
{% if transcript %}
|
||||||
|
Here is the current transcript so far:
|
||||||
|
<transcript>
|
||||||
|
{{ transcript }}
|
||||||
|
</transcript>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_final %}
|
||||||
|
{% if speakers|length == 1 %}
|
||||||
|
This is the final segment of the podcast. Make sure to wrap up the presentation and provide a conclusion.
|
||||||
|
{% else %}
|
||||||
|
This is the final segment of the podcast. Make sure to wrap up the conversation and provide a conclusion.
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
You will focus on creating the dialogue for the following segment ONLY:
|
||||||
|
<segment>
|
||||||
|
{{ segment }}
|
||||||
|
</segment>
|
||||||
|
|
||||||
|
{% if speakers|length == 1 %}
|
||||||
|
IMPORTANT: This is a SOLO podcast with only ONE speaker ({{ speaker_names[0] }}). Do NOT invent or add any other speakers.
|
||||||
|
All dialogue entries must use "{{ speaker_names[0] }}" as the speaker name.
|
||||||
|
|
||||||
|
Follow these format requirements strictly:
|
||||||
|
- Use ONLY the speaker name "{{ speaker_names[0] }}" for all dialogue entries.
|
||||||
|
- Do NOT create or invent any additional speakers.
|
||||||
|
- Stick to the segment, do not go further than what's requested. Other agents will do the rest of the podcast.
|
||||||
|
- The transcript must have at least {{ turns }} dialogue segments from the speaker.
|
||||||
|
- The speaker should present the content in an engaging, educational manner.
|
||||||
|
{% else %}
|
||||||
|
Follow these format requirements strictly:
|
||||||
|
- Use the actual speaker names ({{ speaker_names|join(', ') }}) to denote speakers.
|
||||||
|
- Choose which speaker should speak based on their personality, backstory, and the content being discussed.
|
||||||
|
- Stick to the segment, do not go further than what's requested. Other agents will do the rest of the podcast.
|
||||||
|
- The transcript must have at least {{ turns }} turns of messages between the speakers.
|
||||||
|
- Each speaker should contribute meaningfully based on their expertise and personality.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"transcript": [
|
||||||
|
{
|
||||||
|
"speaker": "[Actual Speaker Name]",
|
||||||
|
"dialogue": "[Speaker's dialogue based on their personality and expertise]"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Formatting instructions:
|
||||||
|
{{ format_instructions}}
|
||||||
|
|
||||||
|
|
||||||
|
{% if speakers|length == 1 %}
|
||||||
|
Guidelines for creating the transcript:
|
||||||
|
- Ensure the presentation flows naturally and covers all points in the outline.
|
||||||
|
- Ensure you return the root "transcript" key in your response.
|
||||||
|
- Make the content sound engaging and educational.
|
||||||
|
- Include relevant details from the briefing.
|
||||||
|
- Break up the content into digestible segments with natural transitions.
|
||||||
|
- Use appropriate transitions between topics.
|
||||||
|
- Match the speaker's dialogue to their personality and expertise.
|
||||||
|
- This is a whole podcast so no need to reintroduce the speaker or topics on each segment. Segments are just markers for us to know to change the topics, nothing else.
|
||||||
|
- CRITICAL: There is only ONE speaker. Use ONLY: {{ speaker_names[0] }}. Do NOT invent additional speakers.
|
||||||
|
{% else %}
|
||||||
|
Guidelines for creating the transcript:
|
||||||
|
- Ensure the conversation flows naturally and covers all points in the outline.
|
||||||
|
- Ensure you return the root "transcript" key in your response.
|
||||||
|
- Make the dialogue sound conversational and engaging.
|
||||||
|
- Include relevant details from the briefing.
|
||||||
|
- Avoid long monologues; keep exchanges between speakers balanced.
|
||||||
|
- Use appropriate transitions between topics.
|
||||||
|
- Match each speaker's dialogue to their personality and expertise.
|
||||||
|
- Choose speakers strategically based on who would naturally contribute to each topic.
|
||||||
|
- This is a whole podcast so no need to reintroduce speakers or topics on each segment. Segments are just markers for us to know to change the topics, nothing else.
|
||||||
|
- IMPORTANT: Only use the provided speaker names: {{ speaker_names|join(', ') }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if language %}
|
||||||
|
CRITICAL LANGUAGE REQUIREMENT:
|
||||||
|
- Write ALL dialogue lines exclusively in {{ language }}.
|
||||||
|
- Do NOT use English or any other language, not even for technical terms or proper concepts where a {{ language }} wording exists.
|
||||||
|
- These instructions are written in English, but every spoken line you produce MUST be in {{ language }}.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
IMPORTANT OUTPUT FORMAT:
|
||||||
|
- If you use extended thinking with <think> tags, put ALL your reasoning inside <think></think> tags
|
||||||
|
- Put the final JSON output OUTSIDE and AFTER any <think> tags
|
||||||
|
- Do NOT wrap the JSON in ```json code blocks - return the raw JSON object only
|
||||||
|
- Example correct format:
|
||||||
|
<think>Let me plan the dialogue...</think>
|
||||||
|
{"transcript": [...]}
|
||||||
|
|
||||||
|
When you're ready, provide the transcript.
|
||||||
|
{% if speakers|length == 1 %}
|
||||||
|
Remember, you are creating a realistic solo podcast presentation based on the given information.
|
||||||
|
Make it informative, engaging, and natural-sounding while adhering to the format requirements.
|
||||||
|
There is only ONE speaker - do not add any other speakers.
|
||||||
|
{% else %}
|
||||||
|
Remember, you are creating a realistic podcast conversation based on the given information.
|
||||||
|
Make it informative, engaging, and natural-sounding while adhering to the format requirements.
|
||||||
|
{% endif %}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue