I am new to Django and am developing a flashcards app that I have included a text to speech functionality however every time I select the text to speech button it does not work. I have been able to debug most of the errors but not this one. The error I get from the network is as above the error I get from the terminal is below
Not Found: /deck/rehearse/22/text_to_speech/5/
[08/Jun/2024 14:33:02] “POST /deck/rehearse/22/text_to_speech/5/ HTTP/1.1” 404 5458
views.py
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
import random
from io import BytesIO
def text_to_speech(request, deck_id, card_id=None):
deck = get_object_or_404(Deck, id=deck_id)
cards = deck.card_set.all()
if not cards:
return JsonResponse({'error': 'No cards found for this deck.'}, status=404)
if card_id:
card = get_object_or_404(Card, id=card_id)
else:
card = random.choice(cards)
engine = pyttsx3.init()
# Generate audio data for the question
question_audio_data = BytesIO()
engine.save_to_wav(card.question, question_audio_data)
question_audio_base64 = base64.b64encode(question_audio_data.getvalue()).decode('utf-8')
# Generate audio data for the answer
answer_audio_data = BytesIO()
engine.save_to_wav(card.answer, answer_audio_data)
answer_audio_base64 = base64.b64encode(answer_audio_data.getvalue()).decode('utf-8')
engine.stop()
audio_data = {
'question_audio': question_audio_base64,
'answer_audio': answer_audio_base64,
}
return JsonResponse(audio_data)
def home(request):
if request.user.is_authenticated:
return redirect('all_decks')
else:
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'])
if user is not None:
login(request, user)
return redirect('home')
else:
form = AuthenticationForm()
return render(request, 'login.html', {'form': form})
def show_all_cards(request):
c_list = Card.objects.all()
context = {'list_of_cards': c_list}
return render(request, 'show_all_cards.html', context)
def delete_card(request, card_id):
card_to_delete = Card.objects.get(id=card_id)
card_to_delete.delete()
return redirect('show_all_cards')
def show_all_decks(request):
d_list = Deck.objects.all()
context = {'list_of_decks': d_list}
return render(request, 'all_decks.html', context)
def delete_deck(request, deck_id):
deck_to_delete = Deck.objects.get(id=deck_id)
deck_to_delete.delete()
return redirect('all_decks')
class DeckCreate(CreateView):
form_class = DeckForm
model = Deck
def form_valid(self, form):
f = form.save(commit=False)
f.creator = self.request.user
f.save()
return super().form_valid(form)
def generate_audio(text, output_path):
engine = pyttsx3.init()
engine.save_to_file(text, output_path)
engine.runAndWait()
html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container">
<div class="row">
{% for card in list_of_cards %}
<div class="rehearse_card" id="card-{{ card.id }}">
<div class="card text-center" style="width: 30rem;">
<img src="{% static 'images/FlashCardImage.svg' %}" class="card-img-top" alt="...">
<div class="card-body">
<div class="card-front">
<h4 class="card-title-question">Q: {{ card.question }}</h4>
<button class="btn btn-primary btn-sm" onclick="flipCard('{{ card.id }}')">Flip Card</button>
<button class="btn btn-secondary btn-sm tts-button" data-card-id="{{ card.id }}"
data-question-audio="{{ card.question_audio.url }}">Text to Speech (Question)</button>
</div>
<div class="card-back" style="display: none;">
<h5 class="card-text-answer">A: {{ card.answer }}</h5>
<button class="btn btn-secondary btn-sm tts-button" data-card-id="{{ card.id }}"
data-answer-audio="{{ card.answer_audio.url }}">Text to Speech (Answer)</button>
</div>
</div>
<div class="card-footer">
<small class="text-muted">{{ card.id }} {{ card.deck.title }} · {{ card.deck.subject }}</small>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<script>
function flipCard(cardId) {
const cardFront = document.querySelector(`#card-${cardId} .card-front`);
const cardBack = document.querySelector(`#card-${cardId} .card-back`);
if (cardFront && cardBack) {
cardFront.style.display = cardFront.style.display === 'none' ? 'block' : 'none';
cardBack.style.display = cardBack.style.display === 'none' ? 'block' : 'none';
} else {
console.error('Card elements not found.');
}
}
function toggleTextToSpeech(button) {
const cardId = button.dataset.cardId;
const deckId = window.location.pathname.split('/')[3]; // Assuming the deck_id is the 4th part of the URL path
const questionAudioUrl = button.dataset.questionAudio;
const answerAudioUrl = button.dataset.answerAudio;
const url = `/deck/rehearse/${deckId}/text_to_speech/${cardId}/`;
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}',
},
body: JSON.stringify({}),
})
.then(response => response.json())
.then(data => {
const questionAudio = new Audio(`data:audio/mpeg;base64,${data.question_audio}`);
const answerAudio = new Audio(`data:audio/mpeg;base64,${data.answer_audio}`);
questionAudio.play();
questionAudio.addEventListener('ended', () => {
answerAudio.play();
});
})
.catch(error => {
console.error('Error:', error);
});
}
const ttsButtons = document.querySelectorAll('.tts-button');
ttsButtons.forEach(button => {
button.addEventListener('click', () => toggleTextToSpeech(button));
});
</script>
{% endblock %}
java-script
var visibleCard = 0;
var cardSide = "QudestionSide";
var audioPlayer = null;
function showCard() {
$(".rehearse_card").hide();
$(".rehearse_card:eq(" + visibleCard + ")").show();
$(".rehearse_card:eq(" + visibleCard + ")").find(".card-title-question").show();
$(".rehearse_card:eq(" + visdibleCard + ")").find(".card-answer-audio").show();
}
function flipCard() {
var currentCard = $(".rehearse_card:eq(" + visibleCard + ")");
if (cardSide == "QuestionSide") {
cardSide = "AnswerSide";
currentCard.find(".card-title-question").hide();
currentCard.find(".card-text-answer").show();
} else {
currentCard.find(".card-title-question").show();
currentCard.find(".card-text-answer").hide();
cardSdide = "QuestionSide";
}
}
function showNextCard() {
if (visibleCard == $(".rehearse_card").length - 1) {
visibleCard = 0;
} else {
visibleCard++;
}
showCard();
}
function showPrevCard() {
if (visibleCard == 0) {
visibleCard = $(".rehearse_card").length - 1;
} else {
visibleCard--;
}
showCard();
}
function toggleTextToSpeech(button, questionAudioUrl, answerAudioUrl) {
if (audioPlayer === null) {
audioPlayer = new Audio(questionAudioUrl);
audioPlayer.play();
button.textContent = "Stop Text to Speech";
audioPlayer.addEventListener('ended', function() {
audioPlayer.src = answerAudioUrl;
audioPlayer.play();
});
} else {
audioPlayer.pause();
audioPlayer.currentTime = 0;
audioPlayer = null;
button.textContent = "Text to Speech";
}
}
$(document).ready(function() {
showCard();
$(".tts-button").click(function() {
var questionAudioUrl = $(this).data("question-audio");
var answerAudioUrl = $(this).data("answer-audio");
toggleTextToSpeech(this, questionAudioUrl, answerAudioUrl);
});
});