Skip to content

Commit 6f9c9d0

Browse files
committed
Adds consistent speaker formatting for audio feedback: adjusts script parsing to handle speaker format change and updates Python script to account for new format.
1 parent 9da97b1 commit 6f9c9d0

File tree

2 files changed

+37
-16
lines changed

2 files changed

+37
-16
lines changed

generate_podcast.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -265,19 +265,40 @@ def synthesize(self, script_text: str, speaker_mapping: Dict[str, str], output_f
265265

266266
def _parse_script_segments(self, script_text: str) -> List[Tuple[str, str]]:
267267
segments = []
268+
current_speaker = None
269+
current_text_lines = []
270+
268271
for raw_line in script_text.splitlines():
269272
line = raw_line.strip()
270273
if not line:
271274
continue
272-
m = re.match(r"^(\w+):\s*(.+)$", line)
273-
if not m:
274-
self.logger.info(f"Skipping non-dialogue line for ElevenLabs: '{line}'")
275-
continue
276-
speaker, text = m.group(1).strip(), m.group(2).strip()
277-
# Apply sanitize_text here, after speaker and text are separated
278-
text = sanitize_text(text)
279-
if text:
280-
segments.append((speaker, text))
275+
276+
match = re.match(r"^(\w+)\s*:\s*(.+)$", line)
277+
278+
if match:
279+
# This is a new speaker line.
280+
# First, save the previous speaker's collected text if it exists.
281+
if current_speaker and current_text_lines:
282+
full_text = " ".join(current_text_lines)
283+
# Sanitize the joined text, then remove any newlines for ElevenLabs.
284+
sanitized_text = sanitize_text(full_text).replace('\n', ' ').replace('\r', '')
285+
if sanitized_text:
286+
segments.append((current_speaker, sanitized_text))
287+
288+
# Start the new speaker's block.
289+
current_speaker = match.group(1).strip()
290+
current_text_lines = [match.group(2).strip()]
291+
elif current_speaker:
292+
# This is a continuation of the current speaker's dialogue.
293+
current_text_lines.append(line)
294+
295+
# After the loop, add the last speaker's segment if it exists.
296+
if current_speaker and current_text_lines:
297+
full_text = " ".join(current_text_lines)
298+
sanitized_text = sanitize_text(full_text).replace('\n', ' ').replace('\r', '')
299+
if sanitized_text:
300+
segments.append((current_speaker, sanitized_text))
301+
281302
return segments
282303

283304

@@ -396,10 +417,10 @@ def sanitize_app_settings_for_backend(app_settings: Dict[str, Any]) -> Dict[str,
396417
clean_elevenlabs = {}
397418
for speaker, data in elevenlabs_voices.items():
398419
if isinstance(data, dict):
399-
elevenlabs_mapping_clean[speaker] = data.get('id', '')
420+
clean_elevenlabs[speaker] = data.get('id', '')
400421
else:
401422
# Legacy format: use the string as-is
402-
elevenlabs_mapping_clean[speaker] = data
423+
clean_elevenlabs[speaker] = data
403424
clean_settings["speaker_voices_elevenlabs"] = clean_elevenlabs
404425

405426
return clean_settings

templates/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ <h3>Asset Credits</h3>
552552
}
553553

554554
function cleanScript(text) {
555-
return text.split('\n').filter(line => /^\s*\w+:\s*.+/.test(line)).join('\n');
555+
return text.split('\n').filter(line => /^\s*\w+\s*:\s*.+/.test(line)).join('\n');
556556
}
557557

558558
function validateSpeakersInUI() {
@@ -568,7 +568,7 @@ <h3>Asset Credits</h3>
568568
const scriptText = scriptTextarea.value;
569569
const combinedText = (instructionText.trim() ? instructionText + '\n' : '') + scriptText;
570570

571-
const speakersInScript = (combinedText.match(/^\s*(\w+):/gm) || []).map(s => s.match(/^\s*(\w+):/)[1]);
571+
const speakersInScript = (combinedText.match(/^\s*(\w+)\s*:/gm) || []).map(s => s.match(/^\s*(\w+)\s*:/)[1]);
572572
const uniqueSpeakers = [...new Set(speakersInScript)];
573573

574574
if (uniqueSpeakers.length > 2) {
@@ -596,7 +596,7 @@ <h3>Asset Credits</h3>
596596
let processedLine = line;
597597

598598
// Check if this line contains a speaker (marks the end of the instruction block)
599-
const isSpeakerLine = /^\s*\w+:/.test(line);
599+
const isSpeakerLine = /^\s*\w+\s*:/.test(line);
600600
if (isSpeakerLine) {
601601
instructionBlockEnded = true;
602602
}
@@ -606,7 +606,7 @@ <h3>Asset Credits</h3>
606606

607607
if (isSpeakerLine) {
608608
// Bold speaker names
609-
processedLine = processedLine.replace(/^(\s*)(\w+):/m, '$1<strong>$2:</strong>');
609+
processedLine = processedLine.replace(/^(\s*)(\w+\s*):/m, '$1<strong>$2:</strong>');
610610
} else if (!instructionBlockEnded && line.trim() !== '') {
611611
// If it's an instruction line (before any speaker) and not empty, wrap the whole line in italics.
612612
processedLine = `<em>${processedLine}</em>`;
@@ -747,7 +747,7 @@ <h3>Asset Credits</h3>
747747
const scriptText = scriptTextarea.value; // Use the actual textarea value
748748
const lines = scriptText.split('\n');
749749
const speakersInScript = lines.map(line => {
750-
const match = line.match(/^\s*(\w+):/);
750+
const match = line.match(/^\s*(\w+)\s*:/);
751751
return match ? match[1] : null;
752752
}).filter(Boolean);
753753
const uniqueSpeakers = [...new Set(speakersInScript)];

0 commit comments

Comments
 (0)