Update main.py
Browse files
main.py
CHANGED
|
@@ -802,28 +802,37 @@ def submit_quiz_attempt(quiz_id):
|
|
| 802 |
@app.route('/api/tutor/notes/<uuid:notes_id>/speak', methods=['GET'])
|
| 803 |
def speak_notes(notes_id):
|
| 804 |
user, error = verify_token(request.headers.get('Authorization'))
|
| 805 |
-
if error:
|
| 806 |
-
|
| 807 |
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
|
| 814 |
notes_content = notes_res.data['content']
|
| 815 |
if not notes_content:
|
| 816 |
-
|
| 817 |
|
| 818 |
# --- Generate TTS Audio ---
|
| 819 |
start_time = time.time()
|
| 820 |
logging.info(f"Generating TTS for user {user.id}, notes: {notes_id}")
|
| 821 |
-
audio_bytes = generate_tts_audio(notes_content)
|
| 822 |
logging.info(f"TTS generation took {time.time() - start_time:.2f}s")
|
| 823 |
|
| 824 |
# --- Save Audio to Supabase Storage ---
|
| 825 |
-
#
|
| 826 |
-
bucket_name = 'notes-audio' # Ensure this bucket exists in Supabase Storage
|
| 827 |
destination_path = f'users/{user.id}/{notes_id}.mp3'
|
| 828 |
content_type = 'audio/mpeg'
|
| 829 |
|
|
@@ -836,29 +845,29 @@ def speak_notes(notes_id):
|
|
| 836 |
audio_url = upload_to_supabase_storage(bucket_name, tmp_file_path, destination_path, content_type)
|
| 837 |
logging.info(f"Uploaded TTS audio to: {audio_url}")
|
| 838 |
|
| 839 |
-
|
| 840 |
supabase.table('notes').update({'tts_audio_url': audio_url}).eq('id', notes_id).execute()
|
|
|
|
| 841 |
# Deduct 5 credits after successful generation
|
| 842 |
new_credits = profile_res.data['credits'] - 5
|
| 843 |
supabase.table('profiles').update({'credits': new_credits}).eq('id', user.id).execute()
|
| 844 |
|
| 845 |
-
# OR: Return the URL
|
| 846 |
return jsonify({'success': True, 'audio_url': audio_url})
|
| 847 |
|
| 848 |
finally:
|
| 849 |
-
|
| 850 |
-
|
| 851 |
|
| 852 |
except ConnectionError as e:
|
| 853 |
logging.error(f"Connection error during TTS generation: {e}")
|
| 854 |
return jsonify({'error': f'A backend service is unavailable: {e}'}), 503
|
| 855 |
-
except RuntimeError as e:
|
| 856 |
-
|
| 857 |
-
|
| 858 |
except Exception as e:
|
| 859 |
logging.error(f"Unexpected error generating TTS for user {user.id}, notes {notes_id}: {traceback.format_exc()}")
|
| 860 |
return jsonify({'error': f'An unexpected error occurred: {e}'}), 500
|
| 861 |
|
|
|
|
| 862 |
@app.route('/api/user/performance', methods=['GET'])
|
| 863 |
def get_user_performance():
|
| 864 |
"""Retrieves user's quiz performance and provides simple suggestions."""
|
|
|
|
| 802 |
@app.route('/api/tutor/notes/<uuid:notes_id>/speak', methods=['GET'])
|
| 803 |
def speak_notes(notes_id):
|
| 804 |
user, error = verify_token(request.headers.get('Authorization'))
|
| 805 |
+
if error:
|
| 806 |
+
return jsonify({'error': error['error']}), error['status']
|
| 807 |
|
| 808 |
+
if not supabase or not elevenlabs_client:
|
| 809 |
+
return jsonify({'error': 'Backend service unavailable'}), 503
|
| 810 |
+
|
| 811 |
+
try:
|
| 812 |
+
profile_res = supabase.table('profiles').select('credits', 'suspended').eq('id', user.id).single().execute()
|
| 813 |
+
|
| 814 |
+
if profile_res.data['suspended']:
|
| 815 |
+
return jsonify({'error': 'Account suspended'}), 403
|
| 816 |
+
if profile_res.data['credits'] < 5:
|
| 817 |
+
return jsonify({'error': 'Insufficient credits (Need 5)'}), 402
|
| 818 |
+
|
| 819 |
+
# Fetch notes content
|
| 820 |
+
notes_res = supabase.table('notes').select('content').eq('id', notes_id).single().execute()
|
| 821 |
+
if not notes_res.data or 'content' not in notes_res.data:
|
| 822 |
+
return jsonify({'error': 'Notes not found or missing content'}), 404
|
| 823 |
|
| 824 |
notes_content = notes_res.data['content']
|
| 825 |
if not notes_content:
|
| 826 |
+
return jsonify({'error': 'Notes content is empty, cannot generate audio.'}), 400
|
| 827 |
|
| 828 |
# --- Generate TTS Audio ---
|
| 829 |
start_time = time.time()
|
| 830 |
logging.info(f"Generating TTS for user {user.id}, notes: {notes_id}")
|
| 831 |
+
audio_bytes = generate_tts_audio(notes_content) # Add voice selection if needed
|
| 832 |
logging.info(f"TTS generation took {time.time() - start_time:.2f}s")
|
| 833 |
|
| 834 |
# --- Save Audio to Supabase Storage ---
|
| 835 |
+
bucket_name = 'notes-audio' # Ensure this bucket exists in Supabase Storage
|
|
|
|
| 836 |
destination_path = f'users/{user.id}/{notes_id}.mp3'
|
| 837 |
content_type = 'audio/mpeg'
|
| 838 |
|
|
|
|
| 845 |
audio_url = upload_to_supabase_storage(bucket_name, tmp_file_path, destination_path, content_type)
|
| 846 |
logging.info(f"Uploaded TTS audio to: {audio_url}")
|
| 847 |
|
| 848 |
+
# --- Update notes table with the URL ---
|
| 849 |
supabase.table('notes').update({'tts_audio_url': audio_url}).eq('id', notes_id).execute()
|
| 850 |
+
|
| 851 |
# Deduct 5 credits after successful generation
|
| 852 |
new_credits = profile_res.data['credits'] - 5
|
| 853 |
supabase.table('profiles').update({'credits': new_credits}).eq('id', user.id).execute()
|
| 854 |
|
|
|
|
| 855 |
return jsonify({'success': True, 'audio_url': audio_url})
|
| 856 |
|
| 857 |
finally:
|
| 858 |
+
os.remove(tmp_file_path) # Clean up temporary file
|
|
|
|
| 859 |
|
| 860 |
except ConnectionError as e:
|
| 861 |
logging.error(f"Connection error during TTS generation: {e}")
|
| 862 |
return jsonify({'error': f'A backend service is unavailable: {e}'}), 503
|
| 863 |
+
except RuntimeError as e: # AI generation errors
|
| 864 |
+
logging.error(f"RuntimeError during TTS generation for user {user.id}: {e}")
|
| 865 |
+
return jsonify({'error': str(e)}), 500
|
| 866 |
except Exception as e:
|
| 867 |
logging.error(f"Unexpected error generating TTS for user {user.id}, notes {notes_id}: {traceback.format_exc()}")
|
| 868 |
return jsonify({'error': f'An unexpected error occurred: {e}'}), 500
|
| 869 |
|
| 870 |
+
|
| 871 |
@app.route('/api/user/performance', methods=['GET'])
|
| 872 |
def get_user_performance():
|
| 873 |
"""Retrieves user's quiz performance and provides simple suggestions."""
|