Search in sources :

Example 6 with AudioContributionEvent

use of ai.elimu.model.contributor.AudioContributionEvent in project webapp by elimu-ai.

the class StoryBookParagraphEditController method handleRequest.

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String handleRequest(Model model, @PathVariable Long id, HttpSession session) {
    logger.info("handleRequest");
    StoryBookParagraph storyBookParagraph = storyBookParagraphDao.read(id);
    logger.info("storyBookParagraph: " + storyBookParagraph);
    model.addAttribute("storyBookParagraph", storyBookParagraph);
    // Generate Audio for this StoryBookParagraph (if it has not been done already)
    List<Audio> paragraphAudios = audioDao.readAll(storyBookParagraph);
    if (paragraphAudios.isEmpty()) {
        Calendar timeStart = Calendar.getInstance();
        Language language = Language.valueOf(ConfigHelper.getProperty("content.language"));
        try {
            byte[] audioBytes = GoogleCloudTextToSpeechHelper.synthesizeText(storyBookParagraph.getOriginalText(), language);
            logger.info("audioBytes: " + audioBytes);
            if (audioBytes != null) {
                Audio audio = new Audio();
                audio.setTimeLastUpdate(Calendar.getInstance());
                audio.setContentType(AudioFormat.MP3.getContentType());
                audio.setStoryBookParagraph(storyBookParagraph);
                audio.setTitle("storybook-" + storyBookParagraph.getStoryBookChapter().getStoryBook().getId() + "-ch-" + (storyBookParagraph.getStoryBookChapter().getSortOrder() + 1) + "-par-" + (storyBookParagraph.getSortOrder() + 1));
                audio.setTranscription(storyBookParagraph.getOriginalText());
                audio.setBytes(audioBytes);
                // TODO: Convert from byte[] to File, and extract audio duration
                audio.setDurationMs(null);
                audio.setAudioFormat(AudioFormat.MP3);
                audioDao.create(audio);
                AudioContributionEvent audioContributionEvent = new AudioContributionEvent();
                audioContributionEvent.setContributor((Contributor) session.getAttribute("contributor"));
                audioContributionEvent.setTime(Calendar.getInstance());
                audioContributionEvent.setAudio(audio);
                audioContributionEvent.setRevisionNumber(audio.getRevisionNumber());
                audioContributionEvent.setComment("Google Cloud Text-to-Speech (🤖 auto-generated comment)️");
                audioContributionEvent.setTimeSpentMs(System.currentTimeMillis() - timeStart.getTimeInMillis());
                audioContributionEvent.setPlatform(Platform.WEBAPP);
                audioContributionEventDao.create(audioContributionEvent);
                paragraphAudios = audioDao.readAll(storyBookParagraph);
            }
        } catch (Exception ex) {
            logger.error(ex);
        }
    }
    model.addAttribute("audios", paragraphAudios);
    model.addAttribute("timeStart", System.currentTimeMillis());
    return "content/storybook/paragraph/edit";
}
Also used : Language(ai.elimu.model.v2.enums.Language) Calendar(java.util.Calendar) StoryBookParagraph(ai.elimu.model.content.StoryBookParagraph) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 7 with AudioContributionEvent

use of ai.elimu.model.contributor.AudioContributionEvent in project webapp by elimu-ai.

the class WordEditController method handleRequest.

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String handleRequest(HttpSession session, Model model, @PathVariable Long id) {
    logger.info("handleRequest");
    Word word = wordDao.read(id);
    if (word.getLetterSoundCorrespondences().isEmpty()) {
        autoSelectLetterSoundCorrespondences(word);
    // TODO: display information message to the Contributor that the letter-sound correspondences were auto-selected, and that they should be verified
    }
    model.addAttribute("word", word);
    model.addAttribute("timeStart", System.currentTimeMillis());
    // TODO: sort by letter(s) text
    model.addAttribute("letterSoundCorrespondences", letterSoundCorrespondenceDao.readAllOrderedByUsage());
    model.addAttribute("rootWords", wordDao.readAllOrdered());
    model.addAttribute("emojisByWordId", getEmojisByWordId());
    model.addAttribute("wordTypes", WordType.values());
    model.addAttribute("spellingConsistencies", SpellingConsistency.values());
    model.addAttribute("wordContributionEvents", wordContributionEventDao.readAll(word));
    model.addAttribute("wordPeerReviewEvents", wordPeerReviewEventDao.readAll(word));
    List<Audio> audios = audioDao.readAll(word);
    model.addAttribute("audios", audios);
    // Generate Audio for this Word (if it has not been done already)
    if (audios.isEmpty()) {
        Calendar timeStart = Calendar.getInstance();
        Language language = Language.valueOf(ConfigHelper.getProperty("content.language"));
        try {
            byte[] audioBytes = GoogleCloudTextToSpeechHelper.synthesizeText(word.getText(), language);
            logger.info("audioBytes: " + audioBytes);
            if (audioBytes != null) {
                Audio audio = new Audio();
                audio.setTimeLastUpdate(Calendar.getInstance());
                audio.setContentType(AudioFormat.MP3.getContentType());
                audio.setWord(word);
                audio.setTitle("word_" + word.getText());
                audio.setTranscription(word.getText());
                audio.setBytes(audioBytes);
                // TODO: Convert from byte[] to File, and extract audio duration
                audio.setDurationMs(null);
                audio.setAudioFormat(AudioFormat.MP3);
                audioDao.create(audio);
                audios.add(audio);
                model.addAttribute("audios", audios);
                AudioContributionEvent audioContributionEvent = new AudioContributionEvent();
                audioContributionEvent.setContributor((Contributor) session.getAttribute("contributor"));
                audioContributionEvent.setTime(Calendar.getInstance());
                audioContributionEvent.setAudio(audio);
                audioContributionEvent.setRevisionNumber(audio.getRevisionNumber());
                audioContributionEvent.setComment("Google Cloud Text-to-Speech (🤖 auto-generated comment)️");
                audioContributionEvent.setTimeSpentMs(System.currentTimeMillis() - timeStart.getTimeInMillis());
                audioContributionEvent.setPlatform(Platform.WEBAPP);
                audioContributionEventDao.create(audioContributionEvent);
            }
        } catch (Exception ex) {
            logger.error(ex);
        }
    }
    // Look up variants of the same wordByTextMatch
    model.addAttribute("wordInflections", wordDao.readInflections(word));
    // Look up Multimedia content that has been labeled with this Word
    // TODO: labeled Audios
    List<Emoji> labeledEmojis = emojiDao.readAllLabeled(word);
    model.addAttribute("labeledEmojis", labeledEmojis);
    List<Image> labeledImages = imageDao.readAllLabeled(word);
    model.addAttribute("labeledImages", labeledImages);
    // TODO: labeled Videos
    // Look up StoryBook Paragraphs that contain this Word
    List<StoryBookParagraph> storyBookParagraphsContainingWord = storyBookParagraphDao.readAllContainingWord(word.getText());
    model.addAttribute("storyBookParagraphsContainingWord", storyBookParagraphsContainingWord);
    return "content/word/edit";
}
Also used : Word(ai.elimu.model.content.Word) Calendar(java.util.Calendar) StoryBookParagraph(ai.elimu.model.content.StoryBookParagraph) Image(ai.elimu.model.content.multimedia.Image) Language(ai.elimu.model.v2.enums.Language) Emoji(ai.elimu.model.content.Emoji) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 8 with AudioContributionEvent

use of ai.elimu.model.contributor.AudioContributionEvent in project webapp by elimu-ai.

the class MostRecentContributionsController method handleRequest.

@RequestMapping(method = RequestMethod.GET)
public String handleRequest(Model model) {
    logger.info("handleRequest");
    List<StoryBookContributionEvent> storyBookContributionEvents = storyBookContributionEventDao.readMostRecent(9);
    logger.info("storyBookContributionEvents.size(): " + storyBookContributionEvents.size());
    model.addAttribute("storyBookContributionEvents", storyBookContributionEvents);
    List<AudioContributionEvent> audioContributionEvents = audioContributionEventDao.readMostRecent(10);
    logger.info("audioContributionEvents.size(): " + audioContributionEvents.size());
    model.addAttribute("audioContributionEvents", audioContributionEvents);
    List<WordContributionEvent> wordContributionEvents = wordContributionEventDao.readMostRecent(10);
    logger.info("wordContributionEvents.size(): " + wordContributionEvents.size());
    model.addAttribute("wordContributionEvents", wordContributionEvents);
    List<NumberContributionEvent> numberContributionEvents = numberContributionEventDao.readMostRecent(10);
    logger.info("numberContributionEvents.size(): " + numberContributionEvents.size());
    model.addAttribute("numberContributionEvents", numberContributionEvents);
    List<Contributor> contributorsWithStoryBookContributions = contributorDao.readAllWithStoryBookContributions();
    logger.info("contributorsWithStoryBookContributions.size(): " + contributorsWithStoryBookContributions.size());
    model.addAttribute("contributorsWithStoryBookContributions", contributorsWithStoryBookContributions);
    Map<Long, Long> storyBookContributionsCountMap = new HashMap<>();
    for (Contributor contributor : contributorsWithStoryBookContributions) {
        storyBookContributionsCountMap.put(contributor.getId(), storyBookContributionEventDao.readCount(contributor));
    }
    model.addAttribute("storyBookContributionsCountMap", storyBookContributionsCountMap);
    List<Contributor> contributorsWithAudioContributions = contributorDao.readAllWithAudioContributions();
    logger.info("contributorsWithAudioContributions.size(): " + contributorsWithAudioContributions.size());
    model.addAttribute("contributorsWithAudioContributions", contributorsWithAudioContributions);
    Map<Long, Long> audioContributionsCountMap = new HashMap<>();
    for (Contributor contributor : contributorsWithAudioContributions) {
        audioContributionsCountMap.put(contributor.getId(), audioContributionEventDao.readCount(contributor));
    }
    model.addAttribute("audioContributionsCountMap", audioContributionsCountMap);
    List<Contributor> contributorsWithWordContributions = contributorDao.readAllWithWordContributions();
    logger.info("contributorsWithWordContributions.size(): " + contributorsWithWordContributions.size());
    model.addAttribute("contributorsWithWordContributions", contributorsWithWordContributions);
    Map<Long, Long> wordContributionsCountMap = new HashMap<>();
    for (Contributor contributor : contributorsWithWordContributions) {
        wordContributionsCountMap.put(contributor.getId(), wordContributionEventDao.readCount(contributor));
    }
    model.addAttribute("wordContributionsCountMap", wordContributionsCountMap);
    List<Contributor> contributorsWithNumberContributions = contributorDao.readAllWithNumberContributions();
    logger.info("contributorsWithNumberContributions.size(): " + contributorsWithNumberContributions.size());
    model.addAttribute("contributorsWithNumberContributions", contributorsWithNumberContributions);
    Map<Long, Long> numberContributionsCountMap = new HashMap<>();
    for (Contributor contributor : contributorsWithNumberContributions) {
        numberContributionsCountMap.put(contributor.getId(), numberContributionEventDao.readCount(contributor));
    }
    model.addAttribute("numberContributionsCountMap", numberContributionsCountMap);
    return "contributions/most-recent";
}
Also used : HashMap(java.util.HashMap) Contributor(ai.elimu.model.contributor.Contributor) StoryBookContributionEvent(ai.elimu.model.contributor.StoryBookContributionEvent) NumberContributionEvent(ai.elimu.model.contributor.NumberContributionEvent) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) WordContributionEvent(ai.elimu.model.contributor.WordContributionEvent) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 9 with AudioContributionEvent

use of ai.elimu.model.contributor.AudioContributionEvent in project webapp by elimu-ai.

the class AudioContributionsRestController method getWordsPendingRecording.

/**
 * Get {@link Word}s pending {@link Audio} recording for the current {@link Contributor}.
 */
@RequestMapping(value = "/words", method = RequestMethod.GET)
public String getWordsPendingRecording(HttpServletRequest request, HttpServletResponse response) {
    logger.info("getWordsPendingRecording");
    JSONObject jsonObject = new JSONObject();
    // Lookup the Contributor by ID
    String providerIdGoogle = request.getHeader("providerIdGoogle");
    logger.info("providerIdGoogle: " + providerIdGoogle);
    if (StringUtils.isBlank(providerIdGoogle)) {
        jsonObject.put("result", "error");
        jsonObject.put("errorMessage", "Missing providerIdGoogle");
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        String jsonResponse = jsonObject.toString();
        logger.info("jsonResponse: " + jsonResponse);
        return jsonResponse;
    }
    Contributor contributor = contributorDao.readByProviderIdGoogle(providerIdGoogle);
    logger.info("contributor: " + contributor);
    if (contributor == null) {
        jsonObject.put("result", "error");
        jsonObject.put("errorMessage", "The Contributor was not found.");
        response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
        String jsonResponse = jsonObject.toString();
        logger.info("jsonResponse: " + jsonResponse);
        return jsonResponse;
    }
    // Get the IDs of Words that have already been recorded by the Contributor
    List<AudioContributionEvent> audioContributionEvents = audioContributionEventDao.readAll(contributor);
    logger.info("audioContributionEvents.size(): " + audioContributionEvents.size());
    HashMap<Long, Void> idsOfRecordedWordsHashMap = new HashMap<>();
    for (AudioContributionEvent audioContributionEvent : audioContributionEvents) {
        Audio audio = audioContributionEvent.getAudio();
        Word word = audio.getWord();
        if (word != null) {
            idsOfRecordedWordsHashMap.put(word.getId(), null);
        }
    }
    logger.info("idsOfRecordedWordsHashMap.size(): " + idsOfRecordedWordsHashMap.size());
    // For each Word, check if the Contributor has already contributed a
    // corresponding Audio recording. If not, add it to the list of pending recordings.
    List<Word> wordsPendingAudioRecording = new ArrayList<>();
    for (Word word : wordDao.readAllOrderedByUsage()) {
        if (!idsOfRecordedWordsHashMap.containsKey(word.getId())) {
            wordsPendingAudioRecording.add(word);
        }
    }
    logger.info("wordsPendingAudioRecording.size(): " + wordsPendingAudioRecording.size());
    // Convert to JSON
    JSONArray wordsJsonArray = new JSONArray();
    for (Word word : wordsPendingAudioRecording) {
        WordGson wordGson = JpaToGsonConverter.getWordGson(word);
        String json = new Gson().toJson(wordGson);
        wordsJsonArray.put(new JSONObject(json));
    }
    String jsonResponse = wordsJsonArray.toString();
    logger.info("jsonResponse: " + jsonResponse);
    return jsonResponse;
}
Also used : Word(ai.elimu.model.content.Word) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) JSONArray(org.json.JSONArray) Contributor(ai.elimu.model.contributor.Contributor) Gson(com.google.gson.Gson) WordGson(ai.elimu.model.v2.gson.content.WordGson) WordGson(ai.elimu.model.v2.gson.content.WordGson) JSONObject(org.json.JSONObject) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 10 with AudioContributionEvent

use of ai.elimu.model.contributor.AudioContributionEvent in project webapp by elimu-ai.

the class AudioPeerReviewsRestController method uploadAudioPeerReview.

/**
 * Note: The logic in this method is similar to the one used at {@link AudioPeerReviewEventCreateController#handleSubmit}
 */
@RequestMapping(value = "/words", method = RequestMethod.POST)
public String uploadAudioPeerReview(HttpServletRequest request, HttpServletResponse response, @RequestBody String requestBody) {
    logger.info("uploadAudioPeerReview");
    JSONObject jsonObject = new JSONObject();
    String providerIdGoogle = request.getHeader("providerIdGoogle");
    logger.info("providerIdGoogle: " + providerIdGoogle);
    if (StringUtils.isBlank(providerIdGoogle)) {
        jsonObject.put("result", "error");
        jsonObject.put("errorMessage", "Missing providerIdGoogle");
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        String jsonResponse = jsonObject.toString();
        logger.info("jsonResponse: " + jsonResponse);
        return jsonResponse;
    }
    // Lookup the Contributor by ID
    Contributor contributor = contributorDao.readByProviderIdGoogle(providerIdGoogle);
    logger.info("contributor: " + contributor);
    if (contributor == null) {
        jsonObject.put("result", "error");
        jsonObject.put("errorMessage", "The Contributor was not found.");
        response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
        String jsonResponse = jsonObject.toString();
        logger.info("jsonResponse: " + jsonResponse);
        return jsonResponse;
    }
    try {
        // Convert from Gson (POJO) to JPA/Hibernate
        logger.info("requestBody: " + requestBody);
        AudioPeerReviewEventGson audioPeerReviewEventGson = new Gson().fromJson(requestBody, AudioPeerReviewEventGson.class);
        logger.info("audioPeerReviewEventGson: " + audioPeerReviewEventGson);
        AudioContributionEventGson audioContributionEventGson = audioPeerReviewEventGson.getAudioContributionEvent();
        logger.info("audioContributionEventGson: " + audioContributionEventGson);
        Long audioContributionEventGsonId = audioContributionEventGson.getId();
        logger.info("audioContributionEventGsonId: " + audioContributionEventGsonId);
        AudioContributionEvent audioContributionEvent = audioContributionEventDao.read(audioContributionEventGsonId);
        logger.info("audioContributionEvent: " + audioContributionEvent);
        AudioPeerReviewEvent audioPeerReviewEvent = new AudioPeerReviewEvent();
        audioPeerReviewEvent.setContributor(contributor);
        audioPeerReviewEvent.setAudioContributionEvent(audioContributionEvent);
        audioPeerReviewEvent.setApproved(audioPeerReviewEventGson.isApproved());
        audioPeerReviewEvent.setComment(StringUtils.abbreviate(audioPeerReviewEventGson.getComment(), 1000));
        audioPeerReviewEvent.setTime(audioPeerReviewEventGson.getTime());
        audioPeerReviewEvent.setPlatform(Platform.CROWDSOURCE_APP);
        audioPeerReviewEventDao.create(audioPeerReviewEvent);
        String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/multimedia/audio/edit/" + audioContributionEvent.getAudio().getId();
        DiscordHelper.sendChannelMessage("Audio peer-reviewed: " + contentUrl, "\"" + audioContributionEvent.getAudio().getTranscription() + "\"", "Comment: \"" + audioPeerReviewEvent.getComment() + "\"", audioPeerReviewEvent.isApproved(), null);
        // Update the audio's peer review status
        int approvedCount = 0;
        int notApprovedCount = 0;
        for (AudioPeerReviewEvent peerReviewEvent : audioPeerReviewEventDao.readAll(audioContributionEvent)) {
            if (peerReviewEvent.isApproved()) {
                approvedCount++;
            } else {
                notApprovedCount++;
            }
        }
        logger.info("approvedCount: " + approvedCount);
        logger.info("notApprovedCount: " + notApprovedCount);
        Audio audio = audioContributionEvent.getAudio();
        if (approvedCount >= notApprovedCount) {
            audio.setPeerReviewStatus(PeerReviewStatus.APPROVED);
        } else {
            audio.setPeerReviewStatus(PeerReviewStatus.NOT_APPROVED);
        }
        audioDao.update(audio);
    } catch (Exception ex) {
        logger.error(ex);
        jsonObject.put("result", "error");
        jsonObject.put("errorMessage", ex.getMessage());
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
    String jsonResponse = jsonObject.toString();
    logger.info("jsonResponse: " + jsonResponse);
    return jsonResponse;
}
Also used : JSONObject(org.json.JSONObject) AudioPeerReviewEventGson(ai.elimu.model.v2.gson.crowdsource.AudioPeerReviewEventGson) AudioContributionEventGson(ai.elimu.model.v2.gson.crowdsource.AudioContributionEventGson) Contributor(ai.elimu.model.contributor.Contributor) Gson(com.google.gson.Gson) AudioPeerReviewEventGson(ai.elimu.model.v2.gson.crowdsource.AudioPeerReviewEventGson) AudioContributionEventGson(ai.elimu.model.v2.gson.crowdsource.AudioContributionEventGson) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) AudioPeerReviewEvent(ai.elimu.model.contributor.AudioPeerReviewEvent) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Aggregations

AudioContributionEvent (ai.elimu.model.contributor.AudioContributionEvent)11 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)11 Audio (ai.elimu.model.content.multimedia.Audio)7 Contributor (ai.elimu.model.contributor.Contributor)6 Word (ai.elimu.model.content.Word)4 JSONObject (org.json.JSONObject)4 AudioPeerReviewEvent (ai.elimu.model.contributor.AudioPeerReviewEvent)3 Language (ai.elimu.model.v2.enums.Language)3 Gson (com.google.gson.Gson)3 File (java.io.File)3 Calendar (java.util.Calendar)3 HashMap (java.util.HashMap)3 MultipartFile (org.springframework.web.multipart.MultipartFile)3 StoryBookParagraph (ai.elimu.model.content.StoryBookParagraph)2 Image (ai.elimu.model.content.multimedia.Image)2 WordContributionEvent (ai.elimu.model.contributor.WordContributionEvent)2 AudioContributionEventGson (ai.elimu.model.v2.gson.crowdsource.AudioContributionEventGson)2 AudioPeerReviewEventGson (ai.elimu.model.v2.gson.crowdsource.AudioPeerReviewEventGson)2 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2