fixed logging and elevan labs!

This commit is contained in:
AlxAI 2025-03-17 14:49:40 -07:00
parent 476402a23e
commit f00a037aed
7 changed files with 148 additions and 35 deletions

View file

@ -1,10 +1,62 @@
import { gameState } from "./gameState";
// --- ElevenLabs Text-to-Speech configuration ---
const ELEVENLABS_API_KEY = import.meta.env.VITE_ELEVENLABS_API_KEY || "";
let ELEVENLABS_API_KEY = '';
// Try to load from import.meta.env
try {
// First check if we have the Vite-specific variable
if (import.meta.env.VITE_ELEVENLABS_API_KEY) {
ELEVENLABS_API_KEY = String(import.meta.env.VITE_ELEVENLABS_API_KEY).trim();
// Simplified logging
}
// Fallback to the direct env variable (for dev environments)
else if (import.meta.env.ELEVENLABS_API_KEY) {
ELEVENLABS_API_KEY = String(import.meta.env.ELEVENLABS_API_KEY).trim();
}
// Clean and validate the key
if (ELEVENLABS_API_KEY) {
// Remove any unexpected characters that might have been added
ELEVENLABS_API_KEY = ELEVENLABS_API_KEY.replace(/[^a-zA-Z0-9_\-]/g, '');
console.log(`ElevenLabs API key: ${ELEVENLABS_API_KEY ? 'Valid' : 'Invalid'} (${ELEVENLABS_API_KEY.length} chars)`);
}
} catch (err) {
console.error('Error loading API key:', err);
}
const VOICE_ID = "onwK4e9ZLuTAKqWW03F9";
const MODEL_ID = "eleven_multilingual_v2";
// Test the API key validity directly but don't log unless there's an issue
testElevenLabsKey().catch(err => console.error("Key test failed:", err));
async function testElevenLabsKey() {
if (!ELEVENLABS_API_KEY) {
console.warn("Cannot test API key - none provided");
return;
}
try {
const response = await fetch('https://api.elevenlabs.io/v1/voices', {
method: 'GET',
headers: {
'xi-api-key': ELEVENLABS_API_KEY
}
});
if (response.ok) {
console.log("✅ ElevenLabs API key is valid and ready for TTS");
} else {
const errorText = await response.text().catch(() => 'No error details available');
console.error(`❌ ElevenLabs API key invalid: ${response.status}`);
}
} catch (error) {
console.error("❌ ElevenLabs API connection error");
}
}
/**
* Call ElevenLabs TTS to speak the summary out loud.
* Returns a promise that resolves only after the audio finishes playing (or fails).
@ -13,6 +65,27 @@ const MODEL_ID = "eleven_multilingual_v2";
* @returns Promise that resolves when audio completes or rejects on error
*/
export async function speakSummary(summaryText: string): Promise<void> {
if (!summaryText || summaryText.trim() === '') {
console.warn("No summary text provided to speakSummary function");
return;
}
// Check if the summary is in JSON format and extract the actual summary text
let textToSpeak = summaryText;
try {
// Check if it starts with a JSON format indicator
if (summaryText.trim().startsWith('{') && summaryText.includes('"summary"')) {
const parsedSummary = JSON.parse(summaryText);
if (parsedSummary.summary) {
textToSpeak = parsedSummary.summary;
// clean text, drop /n
textToSpeak = textToSpeak.replace(/\n/g, ' ');
}
}
} catch (error) {
console.warn("Failed to parse summary as JSON");
}
if (!ELEVENLABS_API_KEY) {
console.warn("No ElevenLabs API key found. Skipping TTS.");
return;
@ -23,29 +96,26 @@ export async function speakSummary(summaryText: string): Promise<void> {
try {
// Truncate text to first 100 characters for ElevenLabs
const truncatedText = summaryText.substring(0, 100);
if (truncatedText.length < summaryText.length) {
console.log(`TTS text truncated from ${summaryText.length} to 100 characters`);
}
const truncatedText = textToSpeak.substring(0, 100);
// Hit ElevenLabs TTS endpoint with the truncated text
const headers = {
"xi-api-key": ELEVENLABS_API_KEY,
"Content-Type": "application/json",
"Accept": "audio/mpeg"
};
const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, {
method: "POST",
headers: {
"xi-api-key": ELEVENLABS_API_KEY,
"Content-Type": "application/json",
"Accept": "audio/mpeg"
},
headers: headers,
body: JSON.stringify({
text: truncatedText,
model_id: MODEL_ID,
// Optional fine-tuning parameters
// voice_settings: { stability: 0.3, similarity_boost: 0.8 },
})
});
if (!response.ok) {
throw new Error(`ElevenLabs TTS error: ${response.statusText}`);
throw new Error(`ElevenLabs TTS error: ${response.status}`);
}
// Convert response into a playable blob
@ -62,7 +132,7 @@ export async function speakSummary(summaryText: string): Promise<void> {
resolve();
};
}).catch(err => {
console.error("Audio playback error", err);
console.error("Audio playback error");
// Make sure to clear the flag even if there's an error
gameState.isSpeaking = false;
reject(err);
@ -70,7 +140,7 @@ export async function speakSummary(summaryText: string): Promise<void> {
});
} catch (err) {
console.error("Failed to generate TTS from ElevenLabs:", err);
console.error("Failed to generate TTS from ElevenLabs");
// Make sure to clear the flag if there's any exception
gameState.isSpeaking = false;
}