feat: reuse markdown extraction logic for TTS spoken tokens

- extractSpokenTokens now detects if input is already markdown format
- Updated prompt to handle both markdown and HTML input
- Added markdown to plain text conversion in prompt (bold, links)
- processContentWithHermes now delegates to extractSpokenTokens
- Consistent processing pipeline whether from Batman button or Read Page
- Better reuse of extractWebpageContent markdown format
This commit is contained in:
Russell Ballestrini 2025-07-03 20:28:18 -04:00
parent 4dc9568079
commit beab5d01a8

View file

@ -100,75 +100,19 @@ export async function speakTextDirect(text, voice = "alloy", rate = 0.9) {
}
}
// Process page content using Hermes
// Process page content using Hermes (deprecated - use extractSpokenTokens instead)
export async function processContentWithHermes(content) {
const payload = {
model: getSelectedModel(),
messages: [
{
role: "system",
content: `Extract the exact main content of the article.
Avoid reading ads.
Do not change or summarize content. Return the same words verbatim.
When you encounter a list or bullets, add . . . to make the TTS pause between items.
Try to stay as close to the truth of the original version as possible. Start with the title of the post and then jump into it.
Do not mention the TTS stream just do the work!
Remember your only goal is to extract the entire & exact main content of the article.
Ready? Breath and then return a stream of tokens to be used in a TTS system.
`,
},
{
role: "user",
content: content,
},
],
temperature: 0,
max_tokens: 76000,
};
console.log(
"Sending payload to LLM for spoken tokens:",
JSON.stringify(payload, null, 2),
);
try {
const response = await fetch(
`${getSelectedModelEndpoint()}/chat/completions`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify(payload),
},
);
if (!response.ok) {
const errorText = await response.text();
console.error(`HTTP error! status: ${response.status}`, errorText);
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.choices[0].message.content;
} catch (error) {
console.error("Error in processContentWithHermes:", error);
throw error;
}
// Just call extractSpokenTokens for consistency
return await extractSpokenTokens(content);
}
// Extract spoken tokens using Hermes - for Read Page functionality
export async function extractSpokenTokens(content) {
// Pre-clean content with JavaScript to help Hermes
const preCleanedContent = content
// If content is already markdown from extractWebpageContent, use it directly
// Otherwise, pre-clean HTML content
const isMarkdown = content.includes('**Page Title**:') || content.includes('[') && content.includes('](');
const preCleanedContent = isMarkdown ? content : content
// Remove script and style tags completely
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
@ -190,15 +134,16 @@ export async function extractSpokenTokens(content) {
messages: [
{
role: "system",
content: `You are extracting the main article content for text-to-speech. The input has been pre-cleaned of scripts and ads.
content: `You are extracting the main article content for text-to-speech. The input may be markdown or pre-cleaned HTML.
Your task:
1. Find and extract the main article content (title, subtitle, body text)
2. Preserve the exact wording - do not summarize or paraphrase
3. Skip navigation menus, sidebars, footers, and advertisements
4. For lists or bullet points, add "..." between items for natural pauses
5. Remove any remaining HTML tags but keep the text inside them
6. Start with the article title, then the main content
5. Convert markdown to plain text: **bold** → bold, [text](url) → text
6. Remove any remaining HTML tags but keep the text inside them
7. Start with the article title, then the main content
Return only the article text ready for TTS, nothing else.`,
},