Search in sources :

Example 26 with Image

use of ai.elimu.model.content.multimedia.Image in project webapp by elimu-ai.

the class StringToImageConverter method convert.

/**
 * Convert Image id to Image entity
 */
public Image convert(String id) {
    if (StringUtils.isBlank(id)) {
        return null;
    } else {
        Long imageId = Long.parseLong(id);
        Image word = imageDao.read(imageId);
        return word;
    }
}
Also used : Image(ai.elimu.model.content.multimedia.Image)

Example 27 with Image

use of ai.elimu.model.content.multimedia.Image in project webapp by elimu-ai.

the class StoryBookCreateFromEPubController method handleSubmit.

@RequestMapping(method = RequestMethod.POST)
public String handleSubmit(StoryBook storyBook, @RequestParam("bytes") MultipartFile multipartFile, BindingResult result, Model model, HttpServletRequest request, HttpSession session) throws IOException {
    logger.info("handleSubmit");
    Image storyBookCoverImage = null;
    List<StoryBookChapter> storyBookChapters = new ArrayList<>();
    List<StoryBookParagraph> storyBookParagraphs = new ArrayList<>();
    if (multipartFile.isEmpty()) {
        result.rejectValue("bytes", "NotNull");
    } else {
        String contentType = multipartFile.getContentType();
        logger.info("contentType: " + contentType);
        String name = multipartFile.getName();
        logger.info("name: " + name);
        String originalFilename = multipartFile.getOriginalFilename();
        logger.info("originalFilename: " + originalFilename);
        long size = multipartFile.getSize();
        logger.info("size: " + size + " (" + (size / 1024) + "kB)");
        byte[] ePubBytes = multipartFile.getBytes();
        logger.info("ePubBytes.length: " + (ePubBytes.length / 1024 / 1024) + "MB");
        List<File> filesInEPub = unzipFiles(ePubBytes, originalFilename);
        logger.info("filesInEPub.size(): " + filesInEPub.size());
        // Extract the ePUB's metadata from its OPF file
        File opfFile = null;
        for (File file : filesInEPub) {
            if (file.getName().endsWith(".opf")) {
                opfFile = file;
            }
        }
        logger.info("opfFile: \"" + opfFile + "\"");
        if (opfFile == null) {
            throw new IllegalArgumentException("The OPF file was not found");
        } else {
            String title = EPubMetadataExtractionHelper.extractTitleFromOpfFile(opfFile);
            logger.info("title: \"" + title + "\"");
            storyBook.setTitle(title);
            String description = EPubMetadataExtractionHelper.extractDescriptionFromOpfFile(opfFile);
            logger.info("description: \"" + description + "\"");
            if (StringUtils.isNotBlank(description)) {
                logger.info("description.length(): " + description.length());
                if (description.length() > 1024) {
                    description = description.substring(0, 1023);
                }
                storyBook.setDescription(description);
            }
            storyBookCoverImage = new Image();
            String coverImageReference = EPubMetadataExtractionHelper.extractCoverImageReferenceFromOpfFile(opfFile);
            logger.info("coverImageReference: " + coverImageReference);
            File coverImageFile = new File(opfFile.getParent(), coverImageReference);
            logger.info("coverImageFile: " + coverImageFile);
            logger.info("coverImageFile.exists(): " + coverImageFile.exists());
            URI coverImageUri = coverImageFile.toURI();
            logger.info("coverImageUri: " + coverImageUri);
            byte[] coverImageBytes = IOUtils.toByteArray(coverImageUri);
            storyBookCoverImage.setBytes(coverImageBytes);
            byte[] headerBytes = Arrays.copyOfRange(coverImageBytes, 0, 6);
            // "GIF87a"
            byte[] gifHeader87a = { 71, 73, 70, 56, 55, 97 };
            // "GIF89a"
            byte[] gifHeader89a = { 71, 73, 70, 56, 57, 97 };
            if (Arrays.equals(gifHeader87a, headerBytes) || Arrays.equals(gifHeader89a, headerBytes)) {
                storyBookCoverImage.setContentType("image/gif");
                storyBookCoverImage.setImageFormat(ImageFormat.GIF);
            } else if (coverImageFile.getName().toLowerCase().endsWith(".png")) {
                storyBookCoverImage.setContentType("image/png");
                storyBookCoverImage.setImageFormat(ImageFormat.PNG);
            } else if (coverImageFile.getName().toLowerCase().endsWith(".jpg") || coverImageFile.getName().toLowerCase().endsWith(".jpeg")) {
                storyBookCoverImage.setContentType("image/jpg");
                storyBookCoverImage.setImageFormat(ImageFormat.JPG);
            } else if (coverImageFile.getName().toLowerCase().endsWith(".gif")) {
                storyBookCoverImage.setContentType("image/gif");
                storyBookCoverImage.setImageFormat(ImageFormat.GIF);
            }
            try {
                int[] dominantColor = ImageColorHelper.getDominantColor(storyBookCoverImage.getBytes());
                storyBookCoverImage.setDominantColor("rgb(" + dominantColor[0] + "," + dominantColor[1] + "," + dominantColor[2] + ")");
            } catch (NullPointerException ex) {
            // javax.imageio.IIOException: Unsupported Image Type
            }
            if (storyBookCoverImage.getImageFormat() != ImageFormat.GIF) {
                // Reduce size if large image
                int imageWidth = ImageHelper.getWidth(coverImageBytes);
                logger.info("imageWidth: " + imageWidth + "px");
                if (imageWidth > ImageHelper.MINIMUM_WIDTH) {
                    coverImageBytes = ImageHelper.scaleImage(coverImageBytes, ImageHelper.MINIMUM_WIDTH);
                    storyBookCoverImage.setBytes(coverImageBytes);
                }
            }
        }
        // Extract the ePUB's chapters
        File tableOfContentsFile = null;
        for (File file : filesInEPub) {
            if (file.getName().startsWith("toc.")) {
                tableOfContentsFile = file;
            }
        }
        logger.info("tableOfContentsFile: \"" + tableOfContentsFile + "\"");
        if (tableOfContentsFile == null) {
            throw new IllegalArgumentException("The TOC file was not found");
        } else {
            List<String> chapterReferences = null;
            if (tableOfContentsFile.getName().endsWith(".xhtml")) {
                // StoryBookProvider#GLOBAL_DIGITAL_LIBRARY or StoryBookProvider#LETS_READ_ASIA
                chapterReferences = EPubChapterExtractionHelper.extractChapterReferencesFromTableOfContentsFile(tableOfContentsFile);
            } else if (tableOfContentsFile.getName().endsWith(".ncx")) {
                // StoryBookProvider#STORYWEAVER
                chapterReferences = EPubChapterExtractionHelper.extractChapterReferencesFromTableOfContentsFileNcx(tableOfContentsFile);
            }
            logger.info("chapterReferences.size(): " + chapterReferences.size());
            // Extract each chapter's image (if any) and paragraphs
            for (String chapterReference : chapterReferences) {
                logger.info("chapterReference: \"" + chapterReference + "\"");
                File chapterFile = new File(opfFile.getParent(), chapterReference);
                logger.info("chapterFile: \"" + chapterFile + "\"");
                StoryBookChapter storyBookChapter = new StoryBookChapter();
                storyBookChapter.setSortOrder(storyBookChapters.size());
                storyBookChapters.add(storyBookChapter);
                String chapterImageReference = EPubImageExtractionHelper.extractImageReferenceFromChapterFile(chapterFile);
                logger.info("chapterImageReference: " + chapterImageReference);
                if (StringUtils.isNotBlank(chapterImageReference)) {
                    File chapterImageFile = null;
                    if (chapterImageReference.startsWith("http://") || chapterImageReference.startsWith("https://")) {
                        // Download the file
                        URL sourceUrl = new URL(chapterImageReference);
                        String tmpDir = System.getProperty("java.io.tmpdir");
                        logger.info("tmpDir: " + tmpDir);
                        File tmpDirElimuAi = new File(tmpDir, "elimu-ai");
                        logger.info("tmpDirElimuAi: " + tmpDirElimuAi);
                        logger.info("tmpDirElimuAi.mkdir(): " + tmpDirElimuAi.mkdir());
                        chapterImageFile = new File(tmpDirElimuAi, "chapter-image");
                        logger.warn("Downloading image from " + sourceUrl + " and storing at " + chapterImageFile);
                        // 1000 milliseconds x 10
                        int connectionTimeout = 1000 * 10;
                        // 1000 milliseconds x 10
                        int readTimeout = 1000 * 10;
                        FileUtils.copyURLToFile(sourceUrl, chapterImageFile, connectionTimeout, readTimeout);
                    } else {
                        chapterImageFile = new File(chapterFile.getParent(), chapterImageReference);
                    }
                    logger.info("chapterImageFile: " + chapterImageFile);
                    logger.info("chapterImageFile.exists(): " + chapterImageFile.exists());
                    URI chapterImageUri = chapterImageFile.toURI();
                    logger.info("chapterImageUri: " + chapterImageUri);
                    byte[] chapterImageBytes = IOUtils.toByteArray(chapterImageUri);
                    Image chapterImage = new Image();
                    chapterImage.setBytes(chapterImageBytes);
                    byte[] headerBytes = Arrays.copyOfRange(chapterImageBytes, 0, 6);
                    // "GIF87a"
                    byte[] gifHeader87a = { 71, 73, 70, 56, 55, 97 };
                    // "GIF89a"
                    byte[] gifHeader89a = { 71, 73, 70, 56, 57, 97 };
                    if (Arrays.equals(gifHeader87a, headerBytes) || Arrays.equals(gifHeader89a, headerBytes)) {
                        chapterImage.setContentType("image/gif");
                        chapterImage.setImageFormat(ImageFormat.GIF);
                    } else if (chapterImageFile.getName().toLowerCase().endsWith(".png")) {
                        chapterImage.setContentType("image/png");
                        chapterImage.setImageFormat(ImageFormat.PNG);
                    } else if (chapterImageFile.getName().toLowerCase().endsWith(".jpg") || chapterImageFile.getName().toLowerCase().endsWith(".jpeg")) {
                        chapterImage.setContentType("image/jpg");
                        chapterImage.setImageFormat(ImageFormat.JPG);
                    } else if (chapterImageFile.getName().toLowerCase().endsWith(".gif")) {
                        chapterImage.setContentType("image/gif");
                        chapterImage.setImageFormat(ImageFormat.GIF);
                    }
                    try {
                        int[] dominantColor = ImageColorHelper.getDominantColor(chapterImage.getBytes());
                        chapterImage.setDominantColor("rgb(" + dominantColor[0] + "," + dominantColor[1] + "," + dominantColor[2] + ")");
                    } catch (NullPointerException ex) {
                    // javax.imageio.IIOException: Unsupported Image Type
                    }
                    if (chapterImage.getImageFormat() != ImageFormat.GIF) {
                        // Reduce size if large image
                        int imageWidth = ImageHelper.getWidth(chapterImageBytes);
                        logger.info("imageWidth: " + imageWidth + "px");
                        if (imageWidth > ImageHelper.MINIMUM_WIDTH) {
                            chapterImageBytes = ImageHelper.scaleImage(chapterImageBytes, ImageHelper.MINIMUM_WIDTH);
                            chapterImage.setBytes(chapterImageBytes);
                        }
                    }
                    storyBookChapter.setImage(chapterImage);
                }
                List<String> paragraphs = EPubParagraphExtractionHelper.extractParagraphsFromChapterFile(chapterFile);
                logger.info("paragraphs.size(): " + paragraphs.size());
                for (int i = 0; i < paragraphs.size(); i++) {
                    String paragraph = paragraphs.get(i);
                    logger.info("paragraph: \"" + paragraph + "\"");
                    logger.info("paragraph.length(): " + paragraph.length());
                    StoryBookParagraph storyBookParagraph = new StoryBookParagraph();
                    storyBookParagraph.setStoryBookChapter(storyBookChapter);
                    storyBookParagraph.setSortOrder(i);
                    if (paragraph.length() > 1024) {
                        logger.warn("Reducing the length of the paragraph to its initial 1,024 characters.");
                        paragraph = paragraph.substring(0, 1023);
                    }
                    storyBookParagraph.setOriginalText(paragraph);
                    // Note: updating the paragraph's list of Words is handled by the ParagraphWordScheduler
                    storyBookParagraphs.add(storyBookParagraph);
                }
            }
        }
    }
    if (result.hasErrors()) {
        return "content/storybook/create-from-epub";
    } else {
        // Store the StoryBook in the database
        storyBook.setTimeLastUpdate(Calendar.getInstance());
        storyBookDao.create(storyBook);
        StoryBookContributionEvent storyBookContributionEvent = new StoryBookContributionEvent();
        storyBookContributionEvent.setContributor((Contributor) session.getAttribute("contributor"));
        storyBookContributionEvent.setTime(Calendar.getInstance());
        storyBookContributionEvent.setStoryBook(storyBook);
        storyBookContributionEvent.setRevisionNumber(storyBook.getRevisionNumber());
        storyBookContributionEvent.setComment("Uploaded ePUB file (🤖 auto-generated comment)");
        storyBookContributionEvent.setTimeSpentMs(System.currentTimeMillis() - Long.valueOf(request.getParameter("timeStart")));
        storyBookContributionEvent.setPlatform(Platform.WEBAPP);
        storyBookContributionEventDao.create(storyBookContributionEvent);
        // Store the StoryBook's cover image in the database, and assign it to the StoryBook
        storyBookCoverImage.setTitle("storybook-" + storyBook.getId() + "-cover");
        imageDao.create(storyBookCoverImage);
        storeImageContributionEvent(storyBookCoverImage, session, request);
        storyBook.setCoverImage(storyBookCoverImage);
        storyBookDao.update(storyBook);
        // Store the StoryBookChapters in the database
        int chapterSortOrder = 0;
        for (StoryBookChapter storyBookChapter : storyBookChapters) {
            storyBookChapter.setStoryBook(storyBook);
            // Get the paragraphs associated with this chapter
            List<StoryBookParagraph> storyBookParagraphsAssociatedWithChapter = new ArrayList<>();
            for (StoryBookParagraph storyBookParagraph : storyBookParagraphs) {
                if (storyBookParagraph.getStoryBookChapter().getSortOrder().equals(storyBookChapter.getSortOrder())) {
                    storyBookParagraphsAssociatedWithChapter.add(storyBookParagraph);
                }
            }
            logger.info("storyBookParagraphsAssociatedWithChapter.size(): " + storyBookParagraphsAssociatedWithChapter.size());
            // Exclude chapters containing book metadata
            boolean isMetadata = false;
            for (StoryBookParagraph storyBookParagraph : storyBookParagraphsAssociatedWithChapter) {
                String originalTextLowerCase = storyBookParagraph.getOriginalText().toLowerCase();
                if (originalTextLowerCase.contains("author: ") || originalTextLowerCase.contains("illustrator: ") || originalTextLowerCase.contains("translator: ") || originalTextLowerCase.contains("creative commons") || originalTextLowerCase.contains("pratham books") || originalTextLowerCase.contains("storyweaver") || originalTextLowerCase.contains("copyright page")) {
                    isMetadata = true;
                    break;
                }
            }
            if (isMetadata) {
                continue;
            }
            // Update the chapter's sort order (in case any of the previous chapters were excluded)
            storyBookChapter.setSortOrder(chapterSortOrder);
            // Store the chapter's image (if any)
            Image chapterImage = storyBookChapter.getImage();
            if (chapterImage != null) {
                chapterImage.setTitle("storybook-" + storyBook.getId() + "-ch-" + (storyBookChapter.getSortOrder() + 1));
                imageDao.create(chapterImage);
                storeImageContributionEvent(chapterImage, session, request);
            }
            // Only store the chapter if it has an image or at least one paragraph
            if ((chapterImage != null) || (!storyBookParagraphsAssociatedWithChapter.isEmpty())) {
                storyBookChapterDao.create(storyBookChapter);
                chapterSortOrder++;
            }
            // Store the chapter's paragraphs in the database
            for (StoryBookParagraph storyBookParagraph : storyBookParagraphsAssociatedWithChapter) {
                storyBookParagraph.setStoryBookChapter(storyBookChapter);
                storyBookParagraphDao.create(storyBookParagraph);
            }
        }
        String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/storybook/edit/" + storyBook.getId();
        String embedThumbnailUrl = null;
        if (storyBook.getCoverImage() != null) {
            embedThumbnailUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/image/" + storyBook.getCoverImage().getId() + "_r" + storyBook.getCoverImage().getRevisionNumber() + "." + storyBook.getCoverImage().getImageFormat().toString().toLowerCase();
        }
        DiscordHelper.sendChannelMessage("Storybook created (imported from ePUB): " + contentUrl, "\"" + storyBookContributionEvent.getStoryBook().getTitle() + "\"", "Comment: \"" + storyBookContributionEvent.getComment() + "\"", null, embedThumbnailUrl);
        return "redirect:/content/storybook/edit/" + storyBook.getId();
    }
}
Also used : StoryBookChapter(ai.elimu.model.content.StoryBookChapter) ArrayList(java.util.ArrayList) StoryBookParagraph(ai.elimu.model.content.StoryBookParagraph) Image(ai.elimu.model.content.multimedia.Image) URI(java.net.URI) URL(java.net.URL) StoryBookContributionEvent(ai.elimu.model.contributor.StoryBookContributionEvent) File(java.io.File) MultipartFile(org.springframework.web.multipart.MultipartFile) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 28 with Image

use of ai.elimu.model.content.multimedia.Image in project webapp by elimu-ai.

the class StoryBookEditController method handleSubmit.

@RequestMapping(value = "/{id}", method = RequestMethod.POST)
public String handleSubmit(@Valid StoryBook storyBook, BindingResult result, Model model, HttpServletRequest request, HttpSession session) {
    logger.info("handleSubmit");
    StoryBook existingStoryBook = storyBookDao.readByTitle(storyBook.getTitle());
    if ((existingStoryBook != null) && !existingStoryBook.getId().equals(storyBook.getId())) {
        result.rejectValue("title", "NonUnique");
    }
    if (result.hasErrors()) {
        model.addAttribute("storyBook", storyBook);
        model.addAttribute("timeStart", System.currentTimeMillis());
        model.addAttribute("contentLicenses", ContentLicense.values());
        List<Image> coverImages = imageDao.readAllOrdered();
        model.addAttribute("coverImages", coverImages);
        model.addAttribute("readingLevels", ReadingLevel.values());
        List<StoryBookChapter> storyBookChapters = storyBookChapterDao.readAll(storyBook);
        model.addAttribute("storyBookChapters", storyBookChapters);
        // Map<StoryBookChapter.id, List<StoryBookParagraph>>
        Map<Long, List<StoryBookParagraph>> paragraphsPerStoryBookChapterMap = new HashMap<>();
        for (StoryBookChapter storyBookChapter : storyBookChapters) {
            paragraphsPerStoryBookChapterMap.put(storyBookChapter.getId(), storyBookParagraphDao.readAll(storyBookChapter));
        }
        model.addAttribute("paragraphsPerStoryBookChapterMap", paragraphsPerStoryBookChapterMap);
        List<String> paragraphs = new ArrayList<>();
        for (StoryBookChapter storyBookChapter : storyBookChapters) {
            List<StoryBookParagraph> storyBookParagraphs = storyBookParagraphDao.readAll(storyBookChapter);
            for (StoryBookParagraph storyBookParagraph : storyBookParagraphs) {
                paragraphs.add(storyBookParagraph.getOriginalText());
            }
        }
        model.addAttribute("storyBookContributionEvents", storyBookContributionEventDao.readAll(storyBook));
        model.addAttribute("storyBookPeerReviewEvents", storyBookPeerReviewEventDao.readAll(storyBook));
        Language language = Language.valueOf(ConfigHelper.getProperty("content.language"));
        Map<String, Integer> wordFrequencyMap = WordFrequencyHelper.getWordFrequency(paragraphs, language);
        model.addAttribute("wordFrequencyMap", wordFrequencyMap);
        Map<String, Word> wordMap = new HashMap<>();
        for (Word word : wordDao.readAllOrdered()) {
            wordMap.put(word.getText(), word);
        }
        model.addAttribute("wordMap", wordMap);
        model.addAttribute("emojisByWordId", getEmojisByWordId());
        Map<String, Integer> letterFrequencyMap = LetterFrequencyHelper.getLetterFrequency(paragraphs, language);
        model.addAttribute("letterFrequencyMap", letterFrequencyMap);
        Map<String, Letter> letterMap = new HashMap<>();
        for (Letter letter : letterDao.readAllOrdered()) {
            letterMap.put(letter.getText(), letter);
        }
        model.addAttribute("letterMap", letterMap);
        return "content/storybook/edit";
    } else {
        storyBook.setTimeLastUpdate(Calendar.getInstance());
        storyBook.setRevisionNumber(storyBook.getRevisionNumber() + 1);
        storyBookDao.update(storyBook);
        StoryBookContributionEvent storyBookContributionEvent = new StoryBookContributionEvent();
        storyBookContributionEvent.setContributor((Contributor) session.getAttribute("contributor"));
        storyBookContributionEvent.setTime(Calendar.getInstance());
        storyBookContributionEvent.setStoryBook(storyBook);
        storyBookContributionEvent.setRevisionNumber(storyBook.getRevisionNumber());
        storyBookContributionEvent.setComment(StringUtils.abbreviate(request.getParameter("contributionComment"), 1000));
        storyBookContributionEvent.setTimeSpentMs(System.currentTimeMillis() - Long.valueOf(request.getParameter("timeStart")));
        storyBookContributionEvent.setPlatform(Platform.WEBAPP);
        storyBookContributionEventDao.create(storyBookContributionEvent);
        String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/storybook/edit/" + storyBook.getId();
        String embedThumbnailUrl = null;
        if (storyBook.getCoverImage() != null) {
            embedThumbnailUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/image/" + storyBook.getCoverImage().getId() + "_r" + storyBook.getCoverImage().getRevisionNumber() + "." + storyBook.getCoverImage().getImageFormat().toString().toLowerCase();
        }
        DiscordHelper.sendChannelMessage("Storybook edited: " + contentUrl, "\"" + storyBookContributionEvent.getStoryBook().getTitle() + "\"", "Comment: \"" + storyBookContributionEvent.getComment() + "\"", null, embedThumbnailUrl);
        // Refresh REST API cache
        storyBooksJsonService.refreshStoryBooksJSONArray();
        return "redirect:/content/storybook/list#" + storyBook.getId();
    }
}
Also used : StoryBookChapter(ai.elimu.model.content.StoryBookChapter) StoryBook(ai.elimu.model.content.StoryBook) Word(ai.elimu.model.content.Word) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) StoryBookParagraph(ai.elimu.model.content.StoryBookParagraph) Image(ai.elimu.model.content.multimedia.Image) Letter(ai.elimu.model.content.Letter) StoryBookContributionEvent(ai.elimu.model.contributor.StoryBookContributionEvent) Language(ai.elimu.model.v2.enums.Language) ArrayList(java.util.ArrayList) List(java.util.List) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 29 with Image

use of ai.elimu.model.content.multimedia.Image in project webapp by elimu-ai.

the class StoryBookChapterDeleteController method handleRequest.

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String handleRequest(HttpSession session, @PathVariable Long storyBookId, @PathVariable Long id) {
    logger.info("handleRequest");
    Contributor contributor = (Contributor) session.getAttribute("contributor");
    logger.info("contributor.getRoles(): " + contributor.getRoles());
    if (!contributor.getRoles().contains(Role.EDITOR)) {
        // TODO: return HttpStatus.FORBIDDEN
        throw new IllegalAccessError("Missing role for access");
    }
    StoryBookChapter storyBookChapterToBeDeleted = storyBookChapterDao.read(id);
    logger.info("storyBookChapterToBeDeleted: " + storyBookChapterToBeDeleted);
    logger.info("storyBookChapterToBeDeleted.getSortOrder(): " + storyBookChapterToBeDeleted.getSortOrder());
    // Delete the chapter's paragraphs
    List<StoryBookParagraph> storyBookParagraphs = storyBookParagraphDao.readAll(storyBookChapterToBeDeleted);
    logger.info("storyBookParagraphs.size(): " + storyBookParagraphs.size());
    for (StoryBookParagraph storyBookParagraphToBeDeleted : storyBookParagraphs) {
        // Delete the paragraph's reference from corresponding audios (if any)
        List<Audio> paragraphAudios = audioDao.readAll(storyBookParagraphToBeDeleted);
        for (Audio paragraphAudio : paragraphAudios) {
            paragraphAudio.setStoryBookParagraph(null);
            audioDao.update(paragraphAudio);
        }
        logger.info("Deleting StoryBookParagraph with ID " + storyBookParagraphToBeDeleted.getId());
        storyBookParagraphDao.delete(storyBookParagraphToBeDeleted);
    }
    // Delete the chapter
    logger.info("Deleting StoryBookChapter with ID " + storyBookChapterToBeDeleted.getId());
    storyBookChapterDao.delete(storyBookChapterToBeDeleted);
    // Delete the chapter's image (if any)
    Image chapterImage = storyBookChapterToBeDeleted.getImage();
    logger.info("chapterImage: " + chapterImage);
    if (chapterImage != null) {
        // Remove content labels
        chapterImage.setLiteracySkills(null);
        chapterImage.setNumeracySkills(null);
        chapterImage.setLetters(null);
        chapterImage.setNumbers(null);
        chapterImage.setWords(null);
        imageDao.update(chapterImage);
        // Remove contribution events
        for (ImageContributionEvent imageContributionEvent : imageContributionEventDao.readAll(chapterImage)) {
            logger.warn("Deleting ImageContributionEvent from the database");
            imageContributionEventDao.delete(imageContributionEvent);
        }
        logger.warn("Deleting the chapter image from the database");
        imageDao.delete(chapterImage);
    }
    // Update the StoryBook's metadata
    StoryBook storyBook = storyBookChapterToBeDeleted.getStoryBook();
    storyBook.setTimeLastUpdate(Calendar.getInstance());
    storyBook.setRevisionNumber(storyBook.getRevisionNumber() + 1);
    storyBook.setPeerReviewStatus(PeerReviewStatus.PENDING);
    storyBookDao.update(storyBook);
    // Store contribution event
    StoryBookContributionEvent storyBookContributionEvent = new StoryBookContributionEvent();
    storyBookContributionEvent.setContributor(contributor);
    storyBookContributionEvent.setTime(Calendar.getInstance());
    storyBookContributionEvent.setStoryBook(storyBook);
    storyBookContributionEvent.setRevisionNumber(storyBook.getRevisionNumber());
    storyBookContributionEvent.setComment("Deleted storybook chapter " + (storyBookChapterToBeDeleted.getSortOrder() + 1) + " (🤖 auto-generated comment)");
    storyBookContributionEvent.setTimeSpentMs(0L);
    storyBookContributionEvent.setPlatform(Platform.WEBAPP);
    storyBookContributionEventDao.create(storyBookContributionEvent);
    String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/storybook/edit/" + storyBook.getId();
    String embedThumbnailUrl = null;
    if (storyBook.getCoverImage() != null) {
        embedThumbnailUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/image/" + storyBook.getCoverImage().getId() + "_r" + storyBook.getCoverImage().getRevisionNumber() + "." + storyBook.getCoverImage().getImageFormat().toString().toLowerCase();
    }
    DiscordHelper.sendChannelMessage("Storybook chapter deleted: " + contentUrl, "\"" + storyBookContributionEvent.getStoryBook().getTitle() + "\"", "Comment: \"" + storyBookContributionEvent.getComment() + "\"", null, embedThumbnailUrl);
    // Update the sorting order of the remaining chapters
    List<StoryBookChapter> storyBookChapters = storyBookChapterDao.readAll(storyBook);
    logger.info("storyBookChapters.size(): " + storyBookChapters.size());
    for (StoryBookChapter storyBookChapter : storyBookChapters) {
        logger.info("storyBookChapter.getId(): " + storyBookChapter.getId() + ", storyBookChapter.getSortOrder(): " + storyBookChapter.getSortOrder());
        if (storyBookChapter.getSortOrder() > storyBookChapterToBeDeleted.getSortOrder()) {
            // Reduce sort order by 1
            storyBookChapter.setSortOrder(storyBookChapter.getSortOrder() - 1);
            storyBookChapterDao.update(storyBookChapter);
            logger.info("storyBookChapter.getSortOrder() (after update): " + storyBookChapter.getSortOrder());
        }
    }
    // Refresh the REST API cache
    storyBooksJsonService.refreshStoryBooksJSONArray();
    return "redirect:/content/storybook/edit/" + storyBookId;
}
Also used : StoryBookChapter(ai.elimu.model.content.StoryBookChapter) StoryBook(ai.elimu.model.content.StoryBook) ImageContributionEvent(ai.elimu.model.contributor.ImageContributionEvent) Contributor(ai.elimu.model.contributor.Contributor) StoryBookParagraph(ai.elimu.model.content.StoryBookParagraph) Image(ai.elimu.model.content.multimedia.Image) StoryBookContributionEvent(ai.elimu.model.contributor.StoryBookContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 30 with Image

use of ai.elimu.model.content.multimedia.Image in project webapp by elimu-ai.

the class WordCreateController method handleSubmit.

@RequestMapping(method = RequestMethod.POST)
public String handleSubmit(HttpServletRequest request, HttpSession session, @Valid Word word, BindingResult result, Model model) {
    logger.info("handleSubmit");
    Word existingWord = wordDao.readByText(word.getText());
    if (existingWord != null) {
        result.rejectValue("text", "NonUnique");
    }
    if (StringUtils.containsAny(word.getText(), " ")) {
        result.rejectValue("text", "WordSpace");
    }
    if (result.hasErrors()) {
        model.addAttribute("word", word);
        model.addAttribute("timeStart", request.getParameter("timeStart"));
        // 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("audio", audioDao.readByTranscription(word.getText()));
        return "content/word/create";
    } else {
        word.setTimeLastUpdate(Calendar.getInstance());
        wordDao.create(word);
        WordContributionEvent wordContributionEvent = new WordContributionEvent();
        wordContributionEvent.setContributor((Contributor) session.getAttribute("contributor"));
        wordContributionEvent.setTime(Calendar.getInstance());
        wordContributionEvent.setWord(word);
        wordContributionEvent.setRevisionNumber(word.getRevisionNumber());
        wordContributionEvent.setComment(StringUtils.abbreviate(request.getParameter("contributionComment"), 1000));
        wordContributionEvent.setTimeSpentMs(System.currentTimeMillis() - Long.valueOf(request.getParameter("timeStart")));
        wordContributionEvent.setPlatform(Platform.WEBAPP);
        wordContributionEventDao.create(wordContributionEvent);
        String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/word/edit/" + word.getId();
        DiscordHelper.sendChannelMessage("Word created: " + contentUrl, "\"" + wordContributionEvent.getWord().getText() + "\"", "Comment: \"" + wordContributionEvent.getComment() + "\"", null, null);
        // Note: updating the list of Words in StoryBookParagraphs is handled by the ParagraphWordScheduler
        // Label Image with Word of matching title
        Image matchingImage = imageDao.read(word.getText());
        if (matchingImage != null) {
            Set<Word> labeledWords = matchingImage.getWords();
            if (!labeledWords.contains(word)) {
                labeledWords.add(word);
                matchingImage.setWords(labeledWords);
                imageDao.update(matchingImage);
            }
        }
        // Delete syllables that are actual words
        Syllable syllable = syllableDao.readByText(word.getText());
        if (syllable != null) {
            syllableDao.delete(syllable);
        }
        // Generate Audio for this Word (if it has not been done already)
        List<Audio> audios = audioDao.readAll(word);
        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-id-" + word.getId());
                    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);
            }
        }
        return "redirect:/content/word/list#" + word.getId();
    }
}
Also used : Word(ai.elimu.model.content.Word) Calendar(java.util.Calendar) Image(ai.elimu.model.content.multimedia.Image) Language(ai.elimu.model.v2.enums.Language) WordContributionEvent(ai.elimu.model.contributor.WordContributionEvent) AudioContributionEvent(ai.elimu.model.contributor.AudioContributionEvent) Audio(ai.elimu.model.content.multimedia.Audio) Syllable(ai.elimu.model.content.Syllable) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Aggregations

Image (ai.elimu.model.content.multimedia.Image)38 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)31 StoryBook (ai.elimu.model.content.StoryBook)11 Word (ai.elimu.model.content.Word)11 Contributor (ai.elimu.model.Contributor)8 IOException (java.io.IOException)8 Audio (ai.elimu.model.content.multimedia.Audio)7 StoryBookChapter (ai.elimu.model.content.StoryBookChapter)5 StoryBookParagraph (ai.elimu.model.content.StoryBookParagraph)5 StoryBookContributionEvent (ai.elimu.model.contributor.StoryBookContributionEvent)5 ArrayList (java.util.ArrayList)5 Letter (ai.elimu.model.content.Letter)4 Language (ai.elimu.model.v2.enums.Language)4 Test (org.junit.Test)4 Syllable (ai.elimu.model.content.Syllable)3 ImageContributionEvent (ai.elimu.model.contributor.ImageContributionEvent)3 HashSet (java.util.HashSet)3 Emoji (ai.elimu.model.content.Emoji)2 Number (ai.elimu.model.content.Number)2 AudioContributionEvent (ai.elimu.model.contributor.AudioContributionEvent)2