Spaces:
Sleeping
Sleeping
Mike W commited on
Commit ·
2e0855f
1
Parent(s): d0ae679
Fix: Initial runtime errors with integration
Browse files- README.md +1 -1
- index.html +10 -2
- server.py +18 -6
README.md
CHANGED
|
@@ -86,7 +86,7 @@ You will need active accounts and API keys for the following services:
|
|
| 86 |
GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/google-credentials.json"
|
| 87 |
|
| 88 |
# Your DeepL API Key
|
| 89 |
-
|
| 90 |
|
| 91 |
# Your ElevenLabs API Key and Voice ID
|
| 92 |
ELEVENLABS_API_KEY="YOUR_ELEVENLABS_API_KEY"
|
|
|
|
| 86 |
GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/google-credentials.json"
|
| 87 |
|
| 88 |
# Your DeepL API Key
|
| 89 |
+
DEEPL_API_KEY="YOUR_DEEPL_API_KEY"
|
| 90 |
|
| 91 |
# Your ElevenLabs API Key and Voice ID
|
| 92 |
ELEVENLABS_API_KEY="YOUR_ELEVENLABS_API_KEY"
|
index.html
CHANGED
|
@@ -32,11 +32,13 @@
|
|
| 32 |
const connectWebSocket = () => {
|
| 33 |
const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
|
| 34 |
const wsUri = `${proto}//${window.location.host}/ws`;
|
|
|
|
| 35 |
status.textContent = `Status: Connecting to ${wsUri}...`;
|
| 36 |
socket = new WebSocket(wsUri);
|
| 37 |
|
| 38 |
socket.onopen = () => {
|
| 39 |
status.textContent = 'Status: Connected. Ready to start.';
|
|
|
|
| 40 |
startButton.disabled = false;
|
| 41 |
};
|
| 42 |
|
|
@@ -62,13 +64,14 @@
|
|
| 62 |
};
|
| 63 |
|
| 64 |
socket.onclose = () => {
|
|
|
|
| 65 |
status.textContent = 'Status: Disconnected. Please refresh the page.';
|
| 66 |
startButton.disabled = false; // Allow user to try starting again
|
| 67 |
stopButton.disabled = true;
|
| 68 |
};
|
| 69 |
|
| 70 |
socket.onerror = (error) => {
|
| 71 |
-
console.error("WebSocket Error:", error);
|
| 72 |
status.textContent = 'Status: Connection error. Check console for details.';
|
| 73 |
};
|
| 74 |
};
|
|
@@ -121,6 +124,7 @@
|
|
| 121 |
};
|
| 122 |
|
| 123 |
startButton.onclick = async () => {
|
|
|
|
| 124 |
// AudioContext must be created or resumed by a user gesture.
|
| 125 |
if (!audioContext) {
|
| 126 |
audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
|
|
@@ -128,6 +132,7 @@
|
|
| 128 |
await audioContext.resume();
|
| 129 |
}
|
| 130 |
|
|
|
|
| 131 |
navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 16000, channelCount: 1 } })
|
| 132 |
.then(stream => {
|
| 133 |
mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' });
|
|
@@ -137,18 +142,20 @@
|
|
| 137 |
}
|
| 138 |
};
|
| 139 |
mediaRecorder.start(250); // Send data every 250ms
|
|
|
|
| 140 |
|
| 141 |
startButton.disabled = true;
|
| 142 |
stopButton.disabled = false;
|
| 143 |
status.textContent = 'Status: Translating...';
|
| 144 |
})
|
| 145 |
.catch(err => {
|
| 146 |
-
console.error('Error getting user media:', err);
|
| 147 |
status.textContent = 'Error: Could not access microphone.';
|
| 148 |
});
|
| 149 |
};
|
| 150 |
|
| 151 |
stopButton.onclick = () => {
|
|
|
|
| 152 |
if (mediaRecorder) {
|
| 153 |
mediaRecorder.stop();
|
| 154 |
}
|
|
@@ -160,6 +167,7 @@
|
|
| 160 |
};
|
| 161 |
|
| 162 |
window.onload = () => {
|
|
|
|
| 163 |
startButton.disabled = true;
|
| 164 |
stopButton.disabled = true;
|
| 165 |
connectWebSocket(); // Connect automatically on page load
|
|
|
|
| 32 |
const connectWebSocket = () => {
|
| 33 |
const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
|
| 34 |
const wsUri = `${proto}//${window.location.host}/ws`;
|
| 35 |
+
console.log("[CLIENT] Attempting to connect to WebSocket:", wsUri);
|
| 36 |
status.textContent = `Status: Connecting to ${wsUri}...`;
|
| 37 |
socket = new WebSocket(wsUri);
|
| 38 |
|
| 39 |
socket.onopen = () => {
|
| 40 |
status.textContent = 'Status: Connected. Ready to start.';
|
| 41 |
+
console.log("[CLIENT] WebSocket connection opened. Enabling start button.");
|
| 42 |
startButton.disabled = false;
|
| 43 |
};
|
| 44 |
|
|
|
|
| 64 |
};
|
| 65 |
|
| 66 |
socket.onclose = () => {
|
| 67 |
+
console.log("[CLIENT] WebSocket connection closed.");
|
| 68 |
status.textContent = 'Status: Disconnected. Please refresh the page.';
|
| 69 |
startButton.disabled = false; // Allow user to try starting again
|
| 70 |
stopButton.disabled = true;
|
| 71 |
};
|
| 72 |
|
| 73 |
socket.onerror = (error) => {
|
| 74 |
+
console.error("[CLIENT] WebSocket Error:", error);
|
| 75 |
status.textContent = 'Status: Connection error. Check console for details.';
|
| 76 |
};
|
| 77 |
};
|
|
|
|
| 124 |
};
|
| 125 |
|
| 126 |
startButton.onclick = async () => {
|
| 127 |
+
console.log("[CLIENT] Start button clicked.");
|
| 128 |
// AudioContext must be created or resumed by a user gesture.
|
| 129 |
if (!audioContext) {
|
| 130 |
audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
|
|
|
|
| 132 |
await audioContext.resume();
|
| 133 |
}
|
| 134 |
|
| 135 |
+
console.log("[CLIENT] Requesting microphone access...");
|
| 136 |
navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 16000, channelCount: 1 } })
|
| 137 |
.then(stream => {
|
| 138 |
mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' });
|
|
|
|
| 142 |
}
|
| 143 |
};
|
| 144 |
mediaRecorder.start(250); // Send data every 250ms
|
| 145 |
+
console.log("[CLIENT] Microphone access granted. MediaRecorder started.");
|
| 146 |
|
| 147 |
startButton.disabled = true;
|
| 148 |
stopButton.disabled = false;
|
| 149 |
status.textContent = 'Status: Translating...';
|
| 150 |
})
|
| 151 |
.catch(err => {
|
| 152 |
+
console.error('[CLIENT] Error getting user media:', err);
|
| 153 |
status.textContent = 'Error: Could not access microphone.';
|
| 154 |
});
|
| 155 |
};
|
| 156 |
|
| 157 |
stopButton.onclick = () => {
|
| 158 |
+
console.log("[CLIENT] Stop button clicked.");
|
| 159 |
if (mediaRecorder) {
|
| 160 |
mediaRecorder.stop();
|
| 161 |
}
|
|
|
|
| 167 |
};
|
| 168 |
|
| 169 |
window.onload = () => {
|
| 170 |
+
console.log("[CLIENT] Page loaded. Initializing...");
|
| 171 |
startButton.disabled = true;
|
| 172 |
stopButton.disabled = true;
|
| 173 |
connectWebSocket(); // Connect automatically on page load
|
server.py
CHANGED
|
@@ -18,8 +18,16 @@ deepl_key = os.getenv("DEEPL_API_KEY")
|
|
| 18 |
eleven_key = os.getenv("ELEVENLABS_API_KEY")
|
| 19 |
voice_id = os.getenv("ELEVENLABS_VOICE_ID")
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
if not all([google_creds, deepl_key, eleven_key, voice_id]):
|
| 22 |
-
raise ValueError("Missing one or more required API keys
|
| 23 |
|
| 24 |
translator = VoiceTranslator(deepl_key, eleven_key, voice_id)
|
| 25 |
|
|
@@ -69,15 +77,18 @@ async def handle_audio_input(websocket: WebSocket, input_queue: asyncio.Queue):
|
|
| 69 |
|
| 70 |
@app.websocket("/ws") # This was correct, the error was in the old HTML. No change needed here, but confirming it's /ws.
|
| 71 |
async def websocket_endpoint(websocket: WebSocket):
|
|
|
|
| 72 |
await websocket.accept()
|
| 73 |
-
print("WebSocket connection accepted.")
|
| 74 |
|
| 75 |
output_sender_task = None
|
| 76 |
input_handler_task = None
|
| 77 |
|
| 78 |
try:
|
| 79 |
# Start translation and audio processing tasks
|
|
|
|
| 80 |
translator.start_translation()
|
|
|
|
| 81 |
output_sender_task = asyncio.create_task(
|
| 82 |
audio_output_sender(websocket, translator.output_queue)
|
| 83 |
)
|
|
@@ -85,18 +96,19 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
| 85 |
handle_audio_input(websocket, translator.input_queue)
|
| 86 |
)
|
| 87 |
|
|
|
|
| 88 |
await asyncio.gather(input_handler_task, output_sender_task)
|
| 89 |
|
| 90 |
except WebSocketDisconnect:
|
| 91 |
-
print("Client disconnected.")
|
| 92 |
except Exception as e:
|
| 93 |
-
print(f"An error occurred: {e}")
|
| 94 |
finally:
|
| 95 |
-
print("
|
| 96 |
if output_sender_task:
|
| 97 |
output_sender_task.cancel()
|
| 98 |
if input_handler_task:
|
| 99 |
input_handler_task.cancel()
|
| 100 |
translator.stop_translation()
|
| 101 |
await websocket.close()
|
| 102 |
-
print("WebSocket connection closed.")
|
|
|
|
| 18 |
eleven_key = os.getenv("ELEVENLABS_API_KEY")
|
| 19 |
voice_id = os.getenv("ELEVENLABS_VOICE_ID")
|
| 20 |
|
| 21 |
+
# --- Start Debug Prints ---
|
| 22 |
+
print("--- API Key Status ---")
|
| 23 |
+
print(f"GOOGLE_APPLICATION_CREDENTIALS loaded: {bool(google_creds)}")
|
| 24 |
+
print(f"DEEPL_API_KEY loaded: {bool(deepl_key)}")
|
| 25 |
+
print(f"ELEVENLABS_API_KEY loaded: {bool(eleven_key)}")
|
| 26 |
+
print(f"ELEVENLABS_VOICE_ID loaded: {bool(voice_id)}")
|
| 27 |
+
print("----------------------")
|
| 28 |
+
|
| 29 |
if not all([google_creds, deepl_key, eleven_key, voice_id]):
|
| 30 |
+
raise ValueError("CRITICAL: Missing one or more required API keys. Please check your Hugging Face secrets.")
|
| 31 |
|
| 32 |
translator = VoiceTranslator(deepl_key, eleven_key, voice_id)
|
| 33 |
|
|
|
|
| 77 |
|
| 78 |
@app.websocket("/ws") # This was correct, the error was in the old HTML. No change needed here, but confirming it's /ws.
|
| 79 |
async def websocket_endpoint(websocket: WebSocket):
|
| 80 |
+
print("[SERVER] WebSocket endpoint called. Awaiting connection...")
|
| 81 |
await websocket.accept()
|
| 82 |
+
print("[SERVER] WebSocket connection accepted.")
|
| 83 |
|
| 84 |
output_sender_task = None
|
| 85 |
input_handler_task = None
|
| 86 |
|
| 87 |
try:
|
| 88 |
# Start translation and audio processing tasks
|
| 89 |
+
print("[SERVER] Calling translator.start_translation()...")
|
| 90 |
translator.start_translation()
|
| 91 |
+
print("[SERVER] translator.start_translation() returned. Creating tasks...")
|
| 92 |
output_sender_task = asyncio.create_task(
|
| 93 |
audio_output_sender(websocket, translator.output_queue)
|
| 94 |
)
|
|
|
|
| 96 |
handle_audio_input(websocket, translator.input_queue)
|
| 97 |
)
|
| 98 |
|
| 99 |
+
print("[SERVER] Awaiting asyncio.gather for I/O tasks...")
|
| 100 |
await asyncio.gather(input_handler_task, output_sender_task)
|
| 101 |
|
| 102 |
except WebSocketDisconnect:
|
| 103 |
+
print("[SERVER] Client disconnected via WebSocketDisconnect.")
|
| 104 |
except Exception as e:
|
| 105 |
+
print(f"[SERVER] An error occurred in websocket_endpoint: {e}")
|
| 106 |
finally:
|
| 107 |
+
print("[SERVER] Cleaning up tasks and stopping translation...")
|
| 108 |
if output_sender_task:
|
| 109 |
output_sender_task.cancel()
|
| 110 |
if input_handler_task:
|
| 111 |
input_handler_task.cancel()
|
| 112 |
translator.stop_translation()
|
| 113 |
await websocket.close()
|
| 114 |
+
print("[SERVER] WebSocket connection closed.")
|