From 21ad2fd775595764659857bc273b976fc0254391 Mon Sep 17 00:00:00 2001 From: uo287545 Date: Sat, 24 Feb 2024 02:47:08 +0100 Subject: [PATCH 1/7] First version of the question domain. --- src/main/java/com/uniovi/entities/Answer.java | 29 ++++++++ .../java/com/uniovi/entities/Category.java | 24 +++++++ .../java/com/uniovi/entities/Question.java | 70 +++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/main/java/com/uniovi/entities/Answer.java create mode 100644 src/main/java/com/uniovi/entities/Category.java create mode 100644 src/main/java/com/uniovi/entities/Question.java diff --git a/src/main/java/com/uniovi/entities/Answer.java b/src/main/java/com/uniovi/entities/Answer.java new file mode 100644 index 00000000..9ecb8a8d --- /dev/null +++ b/src/main/java/com/uniovi/entities/Answer.java @@ -0,0 +1,29 @@ +package com.uniovi.entities; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Entity +@NoArgsConstructor +public class Answer { + + @Id + @GeneratedValue + private Long id; + + private String text; + private boolean correct; + + @ManyToOne + private Question question; + + public Answer(String text, boolean correct) { + this.text = text; + this.correct = correct; + } + +} \ No newline at end of file diff --git a/src/main/java/com/uniovi/entities/Category.java b/src/main/java/com/uniovi/entities/Category.java new file mode 100644 index 00000000..5ac810b1 --- /dev/null +++ b/src/main/java/com/uniovi/entities/Category.java @@ -0,0 +1,24 @@ +package com.uniovi.entities; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashSet; +import java.util.Set; + +@Getter +@Setter +@Entity +public class Category { + + @Id + private String name; + private String description; + + @OneToMany(mappedBy = "category") + private Set questions = new HashSet<>(); +} diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java new file mode 100644 index 00000000..13970179 --- /dev/null +++ b/src/main/java/com/uniovi/entities/Question.java @@ -0,0 +1,70 @@ +package com.uniovi.entities; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.util.Assert; + +import java.util.Collections; +import java.util.List; + +@Getter +@Setter +@Entity +@NoArgsConstructor +public class Question { + + @Id + @GeneratedValue + private Long id; + + private String statement; + + @OneToMany(mappedBy = "question") + private List options; + + @OneToOne + private Answer correctAnswer; + + @ManyToOne + private Category category; + + public Question(String statement, List options, Answer correctAnswer, Category category) { + Assert.isTrue(options.contains(correctAnswer), "Correct answer must be one of the options"); + this.statement = statement; + this.options = options; + this.correctAnswer = correctAnswer; + this.category = category; + } + + public void addOption(Answer option) { + options.add(option); + } + + public void removeOption(Answer option){ + options.remove(option); + } + + public void getOption(int index){ + options.get(index); + } + + public Answer getOptions(String answer){ + for (Answer option : options) { + if (option.getText().equals(answer)) { + return option; + } + } + return null; + } + + public boolean isCorrectAnswer(Answer answer){ + return answer.isCorrect(); + } + + public void scrambleOptions(){ + Collections.shuffle(options); + } + +} From 5e57f2a64afef7c78a9760c9c9f2e04bb3b761dd Mon Sep 17 00:00:00 2001 From: uo287545 Date: Wed, 28 Feb 2024 22:08:30 +0100 Subject: [PATCH 2/7] Question domain entities, repositories and services added. --- src/main/java/com/uniovi/dto/AnswerDto.java | 17 +++++++++ src/main/java/com/uniovi/dto/CategoryDto.java | 20 ++++++++++ src/main/java/com/uniovi/dto/QuestionDto.java | 22 +++++++++++ .../java/com/uniovi/entities/Category.java | 5 ++- .../java/com/uniovi/entities/Question.java | 18 ++++++++- .../uniovi/repositories/AnswerRepository.java | 12 ++++++ .../repositories/CategoryRepository.java | 7 ++++ .../repositories/QuestionRepository.java | 7 ++++ .../com/uniovi/services/AnswerService.java | 35 ++++++++++++++++++ .../com/uniovi/services/CategoryService.java | 35 ++++++++++++++++++ .../com/uniovi/services/QuestionService.java | 34 +++++++++++++++++ .../services/impl/AnswerServiceImpl.java | 35 ++++++++++++++++++ .../services/impl/CategoryServiceImpl.java | 37 +++++++++++++++++++ .../services/impl/QuestionServiceImpl.java | 37 +++++++++++++++++++ 14 files changed, 318 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/uniovi/dto/AnswerDto.java create mode 100644 src/main/java/com/uniovi/dto/CategoryDto.java create mode 100644 src/main/java/com/uniovi/dto/QuestionDto.java create mode 100644 src/main/java/com/uniovi/repositories/AnswerRepository.java create mode 100644 src/main/java/com/uniovi/repositories/CategoryRepository.java create mode 100644 src/main/java/com/uniovi/repositories/QuestionRepository.java create mode 100644 src/main/java/com/uniovi/services/AnswerService.java create mode 100644 src/main/java/com/uniovi/services/CategoryService.java create mode 100644 src/main/java/com/uniovi/services/QuestionService.java create mode 100644 src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java create mode 100644 src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java create mode 100644 src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java diff --git a/src/main/java/com/uniovi/dto/AnswerDto.java b/src/main/java/com/uniovi/dto/AnswerDto.java new file mode 100644 index 00000000..20ad1e37 --- /dev/null +++ b/src/main/java/com/uniovi/dto/AnswerDto.java @@ -0,0 +1,17 @@ +package com.uniovi.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class AnswerDto { + private Long id; + private String text; + private boolean correct; + +} diff --git a/src/main/java/com/uniovi/dto/CategoryDto.java b/src/main/java/com/uniovi/dto/CategoryDto.java new file mode 100644 index 00000000..6b34b07e --- /dev/null +++ b/src/main/java/com/uniovi/dto/CategoryDto.java @@ -0,0 +1,20 @@ +package com.uniovi.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CategoryDto { + + private Long id; + private String name; + private String description; + private List questions; +} diff --git a/src/main/java/com/uniovi/dto/QuestionDto.java b/src/main/java/com/uniovi/dto/QuestionDto.java new file mode 100644 index 00000000..dac83779 --- /dev/null +++ b/src/main/java/com/uniovi/dto/QuestionDto.java @@ -0,0 +1,22 @@ +package com.uniovi.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class QuestionDto { + + private Long id; + private String statement; + private List options; + private AnswerDto correctAnswer; + private CategoryDto category; + +} diff --git a/src/main/java/com/uniovi/entities/Category.java b/src/main/java/com/uniovi/entities/Category.java index 5ac810b1..efffccc7 100644 --- a/src/main/java/com/uniovi/entities/Category.java +++ b/src/main/java/com/uniovi/entities/Category.java @@ -1,8 +1,8 @@ package com.uniovi.entities; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import lombok.Getter; import lombok.Setter; @@ -16,6 +16,9 @@ public class Category { @Id + @GeneratedValue + private Long id; + private String name; private String description; diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java index 13970179..7e5ad65d 100644 --- a/src/main/java/com/uniovi/entities/Question.java +++ b/src/main/java/com/uniovi/entities/Question.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; @Getter @Setter @@ -19,6 +20,7 @@ public class Question { @GeneratedValue private Long id; + @Column(unique = true) private String statement; @OneToMany(mappedBy = "question") @@ -46,8 +48,8 @@ public void removeOption(Answer option){ options.remove(option); } - public void getOption(int index){ - options.get(index); + public Answer getOption(int index){ + return options.get(index); } public Answer getOptions(String answer){ @@ -67,4 +69,16 @@ public void scrambleOptions(){ Collections.shuffle(options); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Question question = (Question) o; + return Objects.equals(id, question.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/src/main/java/com/uniovi/repositories/AnswerRepository.java b/src/main/java/com/uniovi/repositories/AnswerRepository.java new file mode 100644 index 00000000..b0beb5f8 --- /dev/null +++ b/src/main/java/com/uniovi/repositories/AnswerRepository.java @@ -0,0 +1,12 @@ +package com.uniovi.repositories; + +import com.uniovi.entities.Answer; +import com.uniovi.entities.Question; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface AnswerRepository extends CrudRepository { + + List findByQuestion(Question question); +} diff --git a/src/main/java/com/uniovi/repositories/CategoryRepository.java b/src/main/java/com/uniovi/repositories/CategoryRepository.java new file mode 100644 index 00000000..8f9816bf --- /dev/null +++ b/src/main/java/com/uniovi/repositories/CategoryRepository.java @@ -0,0 +1,7 @@ +package com.uniovi.repositories; + +import com.uniovi.entities.Category; +import org.springframework.data.repository.CrudRepository; + +public interface CategoryRepository extends CrudRepository { +} diff --git a/src/main/java/com/uniovi/repositories/QuestionRepository.java b/src/main/java/com/uniovi/repositories/QuestionRepository.java new file mode 100644 index 00000000..d7a05fac --- /dev/null +++ b/src/main/java/com/uniovi/repositories/QuestionRepository.java @@ -0,0 +1,7 @@ +package com.uniovi.repositories; + +import com.uniovi.entities.Question; +import org.springframework.data.repository.CrudRepository; + +public interface QuestionRepository extends CrudRepository { +} diff --git a/src/main/java/com/uniovi/services/AnswerService.java b/src/main/java/com/uniovi/services/AnswerService.java new file mode 100644 index 00000000..ff2ddd44 --- /dev/null +++ b/src/main/java/com/uniovi/services/AnswerService.java @@ -0,0 +1,35 @@ +package com.uniovi.services; + +import com.uniovi.entities.Answer; +import com.uniovi.entities.Category; +import com.uniovi.entities.Question; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public interface AnswerService { + + /** + * Add a new answer to the database + * + * @param answer Question to be added + */ + void addNewAnswer(Answer answer); + + /** + * Get all the answers for a question + * + * @return A list with all the answers for a question + */ + List getAnswersPerQuestion(Question question); + + /** + * Get an answer by its id + * + * @param id The id of the answer + * @return The answer with the given id + */ + Optional getAnswer(Long id); +} diff --git a/src/main/java/com/uniovi/services/CategoryService.java b/src/main/java/com/uniovi/services/CategoryService.java new file mode 100644 index 00000000..0972fa06 --- /dev/null +++ b/src/main/java/com/uniovi/services/CategoryService.java @@ -0,0 +1,35 @@ +package com.uniovi.services; + +import com.uniovi.entities.Category; +import com.uniovi.entities.Question; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public interface CategoryService { + + /** + * Add a new category to the database + * + * @param category Question to be added + */ + void addNewCategory(Category category); + + /** + * Get all the categories in the database + * + * @return A list with all the categories + */ + List getAllCategories(); + + /** + * Get a category by its id + * + * @param id The id of the category + * @return The category with the given id + */ + Optional getCategory(Long id); + +} diff --git a/src/main/java/com/uniovi/services/QuestionService.java b/src/main/java/com/uniovi/services/QuestionService.java new file mode 100644 index 00000000..9bc96b7d --- /dev/null +++ b/src/main/java/com/uniovi/services/QuestionService.java @@ -0,0 +1,34 @@ +package com.uniovi.services; + +import com.uniovi.dto.QuestionDto; +import com.uniovi.entities.Question; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public interface QuestionService { + + /** + * Add a new question to the database + * + * @param question Question to be added + */ + void addNewQuestion(Question question); + + /** + * Get all the questions in the database + * + * @return A list with all the questions + */ + List getAllQuestions(); + + /** + * Get a question by its id + * + * @param id The id of the question + * @return The question with the given id + */ + Optional getQuestion(Long id); +} diff --git a/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java b/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java new file mode 100644 index 00000000..2bfdaa1d --- /dev/null +++ b/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java @@ -0,0 +1,35 @@ +package com.uniovi.services.impl; + +import com.uniovi.entities.Answer; +import com.uniovi.entities.Question; +import com.uniovi.repositories.AnswerRepository; +import com.uniovi.services.AnswerService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class AnswerServiceImpl implements AnswerService { + + private final AnswerRepository answerRepository; + + public AnswerServiceImpl(AnswerRepository answerRepository) { + this.answerRepository = answerRepository; + } + + @Override + public void addNewAnswer(Answer answer) { + answerRepository.save(answer); + } + + @Override + public List getAnswersPerQuestion(Question question) { + return answerRepository.findByQuestion(question); + } + + @Override + public Optional getAnswer(Long id) { + return answerRepository.findById(id); + } +} diff --git a/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java new file mode 100644 index 00000000..ec4c45be --- /dev/null +++ b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java @@ -0,0 +1,37 @@ +package com.uniovi.services.impl; + +import com.uniovi.entities.Category; +import com.uniovi.repositories.CategoryRepository; +import com.uniovi.services.CategoryService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +public class CategoryServiceImpl implements CategoryService { + + private final CategoryRepository categoryRepository; + + public CategoryServiceImpl(CategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; + } + + @Override + public void addNewCategory(Category category) { + categoryRepository.save(category); + } + + @Override + public List getAllCategories() { + List l = new ArrayList<>(); + categoryRepository.findAll().forEach(l::add); + return l; + } + + @Override + public Optional getCategory(Long id) { + return categoryRepository.findById(id); + } +} diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java new file mode 100644 index 00000000..3cfaf4ce --- /dev/null +++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java @@ -0,0 +1,37 @@ +package com.uniovi.services.impl; + +import com.uniovi.entities.Question; +import com.uniovi.repositories.QuestionRepository; +import com.uniovi.services.QuestionService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +public class QuestionServiceImpl implements QuestionService { + + private final QuestionRepository questionRepository; + + public QuestionServiceImpl(QuestionRepository questionRepository) { + this.questionRepository = questionRepository; + } + + @Override + public void addNewQuestion(Question question) { + questionRepository.save(question); + } + + @Override + public List getAllQuestions() { + List l = new ArrayList<>(); + questionRepository.findAll().forEach(l::add); + return l; + } + + @Override + public Optional getQuestion(Long id) { + return questionRepository.findById(id); + } +} From 4a4068765b5e7fee2a835c3f920155a35e67db4c Mon Sep 17 00:00:00 2001 From: uo287545 Date: Thu, 29 Feb 2024 02:52:18 +0100 Subject: [PATCH 3/7] Removed Wikidata library because of its inefficiency compared with SPARQL queries. Basic generic generation system implemented --- pom.xml | 6 +- .../uniovi/components/QuestionGenerator.java | 138 ++++++++++++++++++ .../generators/AbstractQuestionGenerator.java | 33 +++++ .../generators/QuestionGenerator.java | 17 +++ .../geography/AbstractGeographyGenerator.java | 12 ++ .../geography/CapitalQuestionGenerator.java | 48 ++++++ src/main/java/com/uniovi/entities/Answer.java | 4 + .../java/com/uniovi/entities/Category.java | 13 +- .../java/com/uniovi/entities/Question.java | 10 ++ 9 files changed, 274 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/uniovi/components/QuestionGenerator.java create mode 100644 src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java create mode 100644 src/main/java/com/uniovi/components/generators/QuestionGenerator.java create mode 100644 src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java create mode 100644 src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java diff --git a/pom.xml b/pom.xml index 4b07011b..98942473 100644 --- a/pom.xml +++ b/pom.xml @@ -46,9 +46,9 @@ runtime - org.wikidata.wdtk - wdtk-dumpfiles - 0.14.4 + com.fasterxml.jackson.core + jackson-databind + 2.13.0 org.springframework.boot diff --git a/src/main/java/com/uniovi/components/QuestionGenerator.java b/src/main/java/com/uniovi/components/QuestionGenerator.java new file mode 100644 index 00000000..82f51da9 --- /dev/null +++ b/src/main/java/com/uniovi/components/QuestionGenerator.java @@ -0,0 +1,138 @@ +package com.uniovi.components; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.uniovi.entities.Answer; +import com.uniovi.entities.Category; +import com.uniovi.entities.Question; +import org.springframework.stereotype.Component; + + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.*; + +@Component +public class QuestionGenerator { + + private List test = new ArrayList<>(); + + private static void questionGenerator(String statement, List options, String correctAnswer, Category category){ + List answers = new ArrayList<>(); + //Generamos las respuestas y las añadimos a la lista + for(String s: options){ + Answer answer = new Answer(s, false); + answers.add(answer); + } + //Generamos la respuesta correcta y la añadimos a la lista + Answer correct = new Answer(correctAnswer, true); + answers.add(correct); + + Question question = new Question(statement, answers, correct, category); + System.out.println(question); + } + + public static void main(String[] args) { + HttpClient client = HttpClient.newHttpClient(); + + try { + String sparqlQuery = "#List of present-day countries and capital(s)\n" + + "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" + + "WHERE" + + "{" + + " ?country wdt:P31 wd:Q3624078 ." + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}\n" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}\n" + + " OPTIONAL { ?country wdt:P36 ?capital } ." + + "" + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }\n" + + "}" + + "ORDER BY ?countryLabel"; + + + String endpointUrl = "https://query.wikidata.org/sparql?query=" + + URLEncoder.encode(sparqlQuery, StandardCharsets.UTF_8.toString()) + + "&format=json"; + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(endpointUrl)) + .header("Accept", "application/json") + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + // Process the JSON response here + // Process the JSON response using Jackson ObjectMapper + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonResponse = objectMapper.readTree(response.body()); + + // Access the data from the JSON response + JsonNode resultsNode = jsonResponse.path("results").path("bindings"); + for (JsonNode result : resultsNode) { + String countryLabel = result.path("countryLabel").path("value").asText(); + String capitalLabel = result.path("capitalLabel").path("value").asText(); + + System.out.println("Country: " + countryLabel + ", Capital: " + capitalLabel); + + // Obtener otras capitales del JSON (distintas a la capital correcta) + List allCapitals = getAllCapitals(resultsNode, countryLabel, capitalLabel); + + // Seleccionar tres capitales incorrectas aleatorias + List incorrectCapitals = selectRandomIncorrectCapitals(allCapitals, capitalLabel, 3); + + // Realizar la lógica para generar la pregunta + // Aquí, estoy llamando a tu método questionGenerator con los datos obtenidos + questionGenerator("¿Cuál es la capital de " + countryLabel + "?", + incorrectCapitals, + capitalLabel, + new Category("Geography", "Geography questions")); // Ajusta la categoría según tus necesidades + + //System.out.println("Country: " + countryLabel + ", Capital: " + capitalLabel); + + + } + } catch (JsonMappingException e) { + throw new RuntimeException(e); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private static List getAllCapitals(JsonNode resultsNode, String countryLabel, String correctCapital) { + // Obtener todas las capitales del JSON (distintas a la capital correcta) + List allCapitals = new ArrayList<>(); + for (JsonNode result : resultsNode) { + String capital = result.path("capitalLabel").path("value").asText(); + if (!capital.equals(correctCapital)) { + allCapitals.add(capital); + } + } + return allCapitals; + } + + private static List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) { + // Seleccionar aleatoriamente tres capitales incorrectas distintas a la capital correcta + List incorrectCapitals = new ArrayList<>(); + Random random = new Random(); + while (incorrectCapitals.size() < count && allCapitals.size() > 0) { + int randomIndex = random.nextInt(allCapitals.size()); + String selectedCapital = allCapitals.remove(randomIndex); + if (!selectedCapital.equals(correctCapital) && !incorrectCapitals.contains(selectedCapital)) { + incorrectCapitals.add(selectedCapital); + } + } + return incorrectCapitals; + } +} diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java new file mode 100644 index 00000000..16d55962 --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -0,0 +1,33 @@ +package com.uniovi.components.generators; + +import com.uniovi.entities.Answer; +import com.uniovi.entities.Category; +import com.uniovi.entities.Question; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractQuestionGenerator implements QuestionGenerator{ + + private List questions; + + public void questionGenerator(String statement, List options, String correctAnswer, Category category){ + List answers = new ArrayList<>(); + //Generamos las respuestas y las añadimos a la lista + for(String s: options){ + Answer answer = new Answer(s, false); + answers.add(answer); + } + //Generamos la respuesta correcta y la añadimos a la lista + Answer correct = new Answer(correctAnswer, true); + answers.add(correct); + + Question question = new Question(statement, answers, correct, category); + System.out.println(question); + } + + public List getQuestions() { + return questions; + } + +} diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java new file mode 100644 index 00000000..d2d2507b --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java @@ -0,0 +1,17 @@ +package com.uniovi.components.generators; + +import com.uniovi.entities.Category; +import com.uniovi.entities.Question; + +import java.util.Dictionary; +import java.util.List; + +public interface QuestionGenerator { + + public String getQuery(); + public List getQuestions(); + + public Category getCategory(); + + +} diff --git a/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java new file mode 100644 index 00000000..41736fc1 --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java @@ -0,0 +1,12 @@ +package com.uniovi.components.generators.geography; + +import com.uniovi.components.generators.AbstractQuestionGenerator; +import com.uniovi.entities.Category; + +public abstract class AbstractGeographyGenerator extends AbstractQuestionGenerator { + + @Override + public Category getCategory() { + return new Category("Geography", "Questions about geography"); + } +} diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java new file mode 100644 index 00000000..23a0507c --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -0,0 +1,48 @@ +package com.uniovi.components.generators.geography; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ + @Override + public String getQuery() { + return "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" + + "WHERE {\n" + + " ?country wdt:P31 wd:Q3624078 .\n" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}\n" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}\n" + + " OPTIONAL { ?country wdt:P36 ?capital } .\n" + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }\n" + + "}\n" + + "ORDER BY ?countryLabel"; + } + + private List getAllCapitals(JsonNode resultsNode, String countryLabel, String correctCapital) { + // Obtener todas las capitales del JSON (distintas a la capital correcta) + List allCapitals = new ArrayList<>(); + for (JsonNode result : resultsNode) { + String capital = result.path("capitalLabel").path("value").asText(); + if (!capital.equals(correctCapital)) { + allCapitals.add(capital); + } + } + return allCapitals; + } + + private List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) { + // Seleccionar aleatoriamente tres capitales incorrectas distintas a la capital correcta + List incorrectCapitals = new ArrayList<>(); + Random random = new Random(); + while (incorrectCapitals.size() < count && allCapitals.size() > 0) { + int randomIndex = random.nextInt(allCapitals.size()); + String selectedCapital = allCapitals.remove(randomIndex); + if (!selectedCapital.equals(correctCapital) && !incorrectCapitals.contains(selectedCapital)) { + incorrectCapitals.add(selectedCapital); + } + } + return incorrectCapitals; + } +} diff --git a/src/main/java/com/uniovi/entities/Answer.java b/src/main/java/com/uniovi/entities/Answer.java index 9ecb8a8d..61401b4a 100644 --- a/src/main/java/com/uniovi/entities/Answer.java +++ b/src/main/java/com/uniovi/entities/Answer.java @@ -26,4 +26,8 @@ public Answer(String text, boolean correct) { this.correct = correct; } + public String toString() { + return text; + } + } \ No newline at end of file diff --git a/src/main/java/com/uniovi/entities/Category.java b/src/main/java/com/uniovi/entities/Category.java index efffccc7..cf5d8771 100644 --- a/src/main/java/com/uniovi/entities/Category.java +++ b/src/main/java/com/uniovi/entities/Category.java @@ -1,10 +1,8 @@ package com.uniovi.entities; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; +import jakarta.persistence.*; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.util.HashSet; @@ -13,15 +11,22 @@ @Getter @Setter @Entity +@NoArgsConstructor public class Category { @Id @GeneratedValue private Long id; + @Column(unique = true) private String name; private String description; @OneToMany(mappedBy = "category") private Set questions = new HashSet<>(); + + public Category(String name, String description) { + this.name = name; + this.description = description; + } } diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java index 7e5ad65d..5046a2b0 100644 --- a/src/main/java/com/uniovi/entities/Question.java +++ b/src/main/java/com/uniovi/entities/Question.java @@ -81,4 +81,14 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } + + @Override + public String toString() { + return "Question{" + + "statement='" + statement + '\'' + + ", options=" + options.toString() + + ", correctAnswer=" + correctAnswer.toString() + + ", category=" + category + + '}'; + } } From f355ca04ce62ced78c4cde1928a332772fbd9a1f Mon Sep 17 00:00:00 2001 From: uo287545 Date: Thu, 29 Feb 2024 03:50:41 +0100 Subject: [PATCH 4/7] Improvements in the question generation system --- .../uniovi/components/QuestionGenerator.java | 130 +----------------- .../generators/AbstractQuestionGenerator.java | 52 ++++++- .../geography/CapitalQuestionGenerator.java | 24 +++- 3 files changed, 76 insertions(+), 130 deletions(-) diff --git a/src/main/java/com/uniovi/components/QuestionGenerator.java b/src/main/java/com/uniovi/components/QuestionGenerator.java index 82f51da9..15cb931a 100644 --- a/src/main/java/com/uniovi/components/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/QuestionGenerator.java @@ -1,138 +1,14 @@ package com.uniovi.components; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.uniovi.entities.Answer; -import com.uniovi.entities.Category; -import com.uniovi.entities.Question; +import com.uniovi.components.generators.geography.CapitalQuestionGenerator; import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URLEncoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.*; - @Component public class QuestionGenerator { - private List test = new ArrayList<>(); - - private static void questionGenerator(String statement, List options, String correctAnswer, Category category){ - List answers = new ArrayList<>(); - //Generamos las respuestas y las añadimos a la lista - for(String s: options){ - Answer answer = new Answer(s, false); - answers.add(answer); - } - //Generamos la respuesta correcta y la añadimos a la lista - Answer correct = new Answer(correctAnswer, true); - answers.add(correct); - - Question question = new Question(statement, answers, correct, category); - System.out.println(question); - } - public static void main(String[] args) { - HttpClient client = HttpClient.newHttpClient(); - - try { - String sparqlQuery = "#List of present-day countries and capital(s)\n" + - "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" + - "WHERE" + - "{" + - " ?country wdt:P31 wd:Q3624078 ." + - " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}\n" + - " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}\n" + - " OPTIONAL { ?country wdt:P36 ?capital } ." + - "" + - " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }\n" + - "}" + - "ORDER BY ?countryLabel"; - - - String endpointUrl = "https://query.wikidata.org/sparql?query=" + - URLEncoder.encode(sparqlQuery, StandardCharsets.UTF_8.toString()) + - "&format=json"; - - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(endpointUrl)) - .header("Accept", "application/json") - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - - // Process the JSON response here - // Process the JSON response using Jackson ObjectMapper - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonResponse = objectMapper.readTree(response.body()); - - // Access the data from the JSON response - JsonNode resultsNode = jsonResponse.path("results").path("bindings"); - for (JsonNode result : resultsNode) { - String countryLabel = result.path("countryLabel").path("value").asText(); - String capitalLabel = result.path("capitalLabel").path("value").asText(); - - System.out.println("Country: " + countryLabel + ", Capital: " + capitalLabel); - - // Obtener otras capitales del JSON (distintas a la capital correcta) - List allCapitals = getAllCapitals(resultsNode, countryLabel, capitalLabel); - - // Seleccionar tres capitales incorrectas aleatorias - List incorrectCapitals = selectRandomIncorrectCapitals(allCapitals, capitalLabel, 3); - - // Realizar la lógica para generar la pregunta - // Aquí, estoy llamando a tu método questionGenerator con los datos obtenidos - questionGenerator("¿Cuál es la capital de " + countryLabel + "?", - incorrectCapitals, - capitalLabel, - new Category("Geography", "Geography questions")); // Ajusta la categoría según tus necesidades - - //System.out.println("Country: " + countryLabel + ", Capital: " + capitalLabel); - - - } - } catch (JsonMappingException e) { - throw new RuntimeException(e); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + com.uniovi.components.generators.QuestionGenerator qgen = new CapitalQuestionGenerator(); + System.out.println(qgen.getQuestions()); } - private static List getAllCapitals(JsonNode resultsNode, String countryLabel, String correctCapital) { - // Obtener todas las capitales del JSON (distintas a la capital correcta) - List allCapitals = new ArrayList<>(); - for (JsonNode result : resultsNode) { - String capital = result.path("capitalLabel").path("value").asText(); - if (!capital.equals(correctCapital)) { - allCapitals.add(capital); - } - } - return allCapitals; - } - - private static List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) { - // Seleccionar aleatoriamente tres capitales incorrectas distintas a la capital correcta - List incorrectCapitals = new ArrayList<>(); - Random random = new Random(); - while (incorrectCapitals.size() < count && allCapitals.size() > 0) { - int randomIndex = random.nextInt(allCapitals.size()); - String selectedCapital = allCapitals.remove(randomIndex); - if (!selectedCapital.equals(correctCapital) && !incorrectCapitals.contains(selectedCapital)) { - incorrectCapitals.add(selectedCapital); - } - } - return incorrectCapitals; - } } diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 16d55962..7e3a902d 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -1,15 +1,25 @@ package com.uniovi.components.generators; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.uniovi.entities.Answer; import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public abstract class AbstractQuestionGenerator implements QuestionGenerator{ - private List questions; + private List questions = new ArrayList<>(); + private String query; + protected String statement; public void questionGenerator(String statement, List options, String correctAnswer, Category category){ List answers = new ArrayList<>(); @@ -23,11 +33,51 @@ public void questionGenerator(String statement, List options, String cor answers.add(correct); Question question = new Question(statement, answers, correct, category); + question.scrambleOptions(); System.out.println(question); + questions.add(question); } public List getQuestions() { + HttpClient client = HttpClient.newHttpClient(); + try { + + String endpointUrl = "https://query.wikidata.org/sparql?query=" + + URLEncoder.encode(this.getQuery(), StandardCharsets.UTF_8.toString()) + + "&format=json"; + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(endpointUrl)) + .header("Accept", "application/json") + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + // Process the JSON response using Jackson ObjectMapper + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonResponse = objectMapper.readTree(response.body()); + + // Access the data from the JSON response + JsonNode resultsNode = jsonResponse.path("results").path("bindings"); + + for (JsonNode result : resultsNode) { + + List options = this.generateOptions(resultsNode, result); + String correctAnswer = this.generateCorrectAnswer(result); + String statement = this.getQuestionSubject(result); + questionGenerator(statement, options, correctAnswer, this.getCategory()); + + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return questions; } + protected abstract List generateOptions(JsonNode results, JsonNode result); + protected abstract String generateCorrectAnswer(JsonNode result); + + protected abstract String getQuestionSubject(JsonNode result); + } diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index 23a0507c..408124cd 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -1,12 +1,16 @@ package com.uniovi.components.generators.geography; import com.fasterxml.jackson.databind.JsonNode; - import java.util.ArrayList; import java.util.List; import java.util.Random; public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ + + public CapitalQuestionGenerator() { + this.statement = "What is the capital of "; + } + @Override public String getQuery() { return "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" + @@ -33,7 +37,6 @@ private List getAllCapitals(JsonNode resultsNode, String countryLabel, S } private List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) { - // Seleccionar aleatoriamente tres capitales incorrectas distintas a la capital correcta List incorrectCapitals = new ArrayList<>(); Random random = new Random(); while (incorrectCapitals.size() < count && allCapitals.size() > 0) { @@ -45,4 +48,21 @@ private List selectRandomIncorrectCapitals(List allCapitals, Str } return incorrectCapitals; } + + @Override + protected List generateOptions(JsonNode results, JsonNode result) { + String countryLabel = result.path("countryLabel").path("value").asText(); + String capitalLabel = result.path("capitalLabel").path("value").asText(); + return selectRandomIncorrectCapitals(getAllCapitals(results, countryLabel, capitalLabel), capitalLabel, 3); + } + + @Override + protected String generateCorrectAnswer(JsonNode result) { + return result.path("capitalLabel").path("value").asText(); + } + + @Override + protected String getQuestionSubject(JsonNode result) { + return this.statement + result.path("countryLabel").path("value").asText() + "?"; + } } From dc5466c87813b76d326f805629a49fff82670f7c Mon Sep 17 00:00:00 2001 From: uo287545 Date: Thu, 29 Feb 2024 21:55:05 +0100 Subject: [PATCH 5/7] Question generation system done for Geography question --- pom.xml | 2 +- ...erator.java => QuestionGeneratorTest.java} | 11 ++- .../generators/AbstractQuestionGenerator.java | 1 - .../generators/QuestionGenerator.java | 7 +- .../geography/BorderQuestionGenerator.java | 68 +++++++++++++++++++ .../geography/CapitalQuestionGenerator.java | 5 +- .../ContinentQuestionGeneration.java | 67 ++++++++++++++++++ 7 files changed, 149 insertions(+), 12 deletions(-) rename src/main/java/com/uniovi/components/{QuestionGenerator.java => QuestionGeneratorTest.java} (58%) create mode 100644 src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java create mode 100644 src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java diff --git a/pom.xml b/pom.xml index 98942473..ca84e8a8 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.0 + 2.16.1 org.springframework.boot diff --git a/src/main/java/com/uniovi/components/QuestionGenerator.java b/src/main/java/com/uniovi/components/QuestionGeneratorTest.java similarity index 58% rename from src/main/java/com/uniovi/components/QuestionGenerator.java rename to src/main/java/com/uniovi/components/QuestionGeneratorTest.java index 15cb931a..25c7c42d 100644 --- a/src/main/java/com/uniovi/components/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/QuestionGeneratorTest.java @@ -1,14 +1,19 @@ package com.uniovi.components; import com.uniovi.components.generators.geography.CapitalQuestionGenerator; +import com.uniovi.entities.Question; import org.springframework.stereotype.Component; +import java.util.List; + @Component -public class QuestionGenerator { +public class QuestionGeneratorTest { public static void main(String[] args) { com.uniovi.components.generators.QuestionGenerator qgen = new CapitalQuestionGenerator(); - System.out.println(qgen.getQuestions()); + List q = qgen.getQuestions(); + for(Question question : q){ + System.out.println(question); + } } - } diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 7e3a902d..28f3a3f6 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -34,7 +34,6 @@ public void questionGenerator(String statement, List options, String cor Question question = new Question(statement, answers, correct, category); question.scrambleOptions(); - System.out.println(question); questions.add(question); } diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java index d2d2507b..3ab7a575 100644 --- a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java @@ -3,15 +3,14 @@ import com.uniovi.entities.Category; import com.uniovi.entities.Question; -import java.util.Dictionary; import java.util.List; public interface QuestionGenerator { - public String getQuery(); - public List getQuestions(); + String getQuery(); + List getQuestions(); - public Category getCategory(); + Category getCategory(); } diff --git a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java new file mode 100644 index 00000000..860a5175 --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java @@ -0,0 +1,68 @@ +package com.uniovi.components.generators.geography; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.*; + +public class BorderQuestionGenerator extends AbstractGeographyGenerator{ + + private Set usedCountries = new HashSet<>(); + + public BorderQuestionGenerator() { + this.statement = "Which countries share a border with "; + } + + private List getAllBorderingCountries(JsonNode resultsNode, String correctCountry) { + List allBorderingCountries = new ArrayList<>(); + for (JsonNode result : resultsNode) { + String borderingCountry = result.path("borderingCountryLabel").path("value").asText(); + if (!borderingCountry.equals(correctCountry)) { + allBorderingCountries.add(borderingCountry); + } + } + return allBorderingCountries; + } + + private List selectRandomIncorrectBorderingCountries(List allBorderingCountries, String correctCountry, int count) { + List incorrectBorderingCountries = new ArrayList<>(); + Random random = new Random(); + while (incorrectBorderingCountries.size() < count && allBorderingCountries.size() > 0) { + int randomIndex = random.nextInt(allBorderingCountries.size()); + String selectedBorderingCountry = allBorderingCountries.remove(randomIndex); + if (!selectedBorderingCountry.equals(correctCountry) && !incorrectBorderingCountries.contains(selectedBorderingCountry)) { + incorrectBorderingCountries.add(selectedBorderingCountry); + } + } + return incorrectBorderingCountries; + } + + @Override + protected List generateOptions(JsonNode results, JsonNode result) { + String borderingCountryLabel = result.path("borderingCountryLabel").path("value").asText(); + return selectRandomIncorrectBorderingCountries( + getAllBorderingCountries(results, borderingCountryLabel), + borderingCountryLabel, 3); + } + + @Override + protected String generateCorrectAnswer(JsonNode result) { + return result.path("borderingCountryLabel").path("value").asText(); + } + + @Override + protected String getQuestionSubject(JsonNode result) { + return this.statement + result.path("countryLabel").path("value").asText() + "?"; + } + + @Override + public String getQuery() { + return "SELECT DISTINCT ?country ?countryLabel ?borderingCountry ?borderingCountryLabel\n" + + "WHERE {" + + " ?country wdt:P31 wd:Q3624078 ." + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" + + " ?country wdt:P47 ?borderingCountry ." + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" + + "}"; + } +} diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index 408124cd..cda54a4a 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -24,7 +24,7 @@ public String getQuery() { "ORDER BY ?countryLabel"; } - private List getAllCapitals(JsonNode resultsNode, String countryLabel, String correctCapital) { + private List getAllCapitals(JsonNode resultsNode, String correctCapital) { // Obtener todas las capitales del JSON (distintas a la capital correcta) List allCapitals = new ArrayList<>(); for (JsonNode result : resultsNode) { @@ -51,9 +51,8 @@ private List selectRandomIncorrectCapitals(List allCapitals, Str @Override protected List generateOptions(JsonNode results, JsonNode result) { - String countryLabel = result.path("countryLabel").path("value").asText(); String capitalLabel = result.path("capitalLabel").path("value").asText(); - return selectRandomIncorrectCapitals(getAllCapitals(results, countryLabel, capitalLabel), capitalLabel, 3); + return selectRandomIncorrectCapitals(getAllCapitals(results, capitalLabel), capitalLabel, 3); } @Override diff --git a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java new file mode 100644 index 00000000..8c81316e --- /dev/null +++ b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java @@ -0,0 +1,67 @@ +package com.uniovi.components.generators.geography; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class ContinentQuestionGeneration extends AbstractGeographyGenerator{ + public ContinentQuestionGeneration() { + this.statement = "In which continent is "; + } + + private List getAllContinents(JsonNode resultsNode, String correctContinent) { + // Obtener todas las capitales del JSON (distintas a la capital correcta) + List allContinents = new ArrayList<>(); + for (JsonNode result : resultsNode) { + String continent = result.path("continentLabel").path("value").asText(); + if (!continent.equals(correctContinent)) { + allContinents.add(continent); + } + } + return allContinents; + } + + private List selectRandomIncorrectContinents(List allContinents, String correctContinent, int count) { + List incorrectContinents = new ArrayList<>(); + Random random = new Random(); + while (incorrectContinents.size() < count && allContinents.size() > 0) { + int randomIndex = random.nextInt(allContinents.size()); + String selectedCapital = allContinents.remove(randomIndex); + if (!selectedCapital.equals(correctContinent) && !incorrectContinents.contains(selectedCapital)) { + incorrectContinents.add(selectedCapital); + } + } + return incorrectContinents; + } + + @Override + protected List generateOptions(JsonNode results, JsonNode result) { + String continentLabel = result.path("continentLabel").path("value").asText(); + return selectRandomIncorrectContinents(getAllContinents(results, continentLabel), continentLabel, 3); + } + + @Override + protected String generateCorrectAnswer(JsonNode result) { + return result.path("continentLabel").path("value").asText(); + } + + @Override + protected String getQuestionSubject(JsonNode result) { + return this.statement + result.path("countryLabel").path("value").asText() + "?"; + } + + @Override + public String getQuery() { + return "SELECT DISTINCT ?country ?countryLabel ?continent ?continentLabel\n" + + "WHERE {" + + " ?country wdt:P31 wd:Q3624078 " + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" + + " OPTIONAL { ?country wdt:P30 ?continent } ." + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" + + "}" + + "ORDER BY ?countryLabel"; + } +} From 9b0d319766e47bde60cc674e920a097e24b3f046 Mon Sep 17 00:00:00 2001 From: uo287545 Date: Thu, 29 Feb 2024 23:07:19 +0100 Subject: [PATCH 6/7] Trying to make Categories singletons --- .../components/QuestionGeneratorTest.java | 15 ++++++++---- .../generators/AbstractQuestionGenerator.java | 6 +++++ .../generators/QuestionGenerator.java | 2 ++ .../geography/AbstractGeographyGenerator.java | 7 +++++- .../geography/BorderQuestionGenerator.java | 4 +++- .../geography/CapitalQuestionGenerator.java | 19 ++++++++------- .../ContinentQuestionGeneration.java | 4 +++- .../repositories/CategoryRepository.java | 3 +++ .../repositories/QuestionRepository.java | 2 ++ .../com/uniovi/services/CategoryService.java | 1 + .../services/impl/CategoryServiceImpl.java | 24 ++++++++++++++++--- .../services/impl/QuestionServiceImpl.java | 1 + 12 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/uniovi/components/QuestionGeneratorTest.java b/src/main/java/com/uniovi/components/QuestionGeneratorTest.java index 25c7c42d..cf549d65 100644 --- a/src/main/java/com/uniovi/components/QuestionGeneratorTest.java +++ b/src/main/java/com/uniovi/components/QuestionGeneratorTest.java @@ -1,16 +1,21 @@ package com.uniovi.components; -import com.uniovi.components.generators.geography.CapitalQuestionGenerator; +import com.uniovi.components.generators.QuestionGenerator; import com.uniovi.entities.Question; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; -@Component +@Controller public class QuestionGeneratorTest { - public static void main(String[] args) { - com.uniovi.components.generators.QuestionGenerator qgen = new CapitalQuestionGenerator(); + @Autowired + QuestionGenerator qgen; + + @RequestMapping("/test") + public void test() { List q = qgen.getQuestions(); for(Question question : q){ System.out.println(question); diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 28f3a3f6..cb4d46ab 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -5,6 +5,7 @@ import com.uniovi.entities.Answer; import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import com.uniovi.services.CategoryService; import java.net.URI; import java.net.URLEncoder; @@ -18,9 +19,14 @@ public abstract class AbstractQuestionGenerator implements QuestionGenerator{ private List questions = new ArrayList<>(); + protected final CategoryService categoryService; private String query; protected String statement; + protected AbstractQuestionGenerator(CategoryService categoryService) { + this.categoryService = categoryService; + } + public void questionGenerator(String statement, List options, String correctAnswer, Category category){ List answers = new ArrayList<>(); //Generamos las respuestas y las añadimos a la lista diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java index 3ab7a575..ccaa4dab 100644 --- a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java @@ -2,9 +2,11 @@ import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import org.springframework.stereotype.Component; import java.util.List; +@Component public interface QuestionGenerator { String getQuery(); diff --git a/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java index 41736fc1..d01919e9 100644 --- a/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java @@ -2,11 +2,16 @@ import com.uniovi.components.generators.AbstractQuestionGenerator; import com.uniovi.entities.Category; +import com.uniovi.services.CategoryService; public abstract class AbstractGeographyGenerator extends AbstractQuestionGenerator { + protected AbstractGeographyGenerator(CategoryService categoryService) { + super(categoryService); + } + @Override public Category getCategory() { - return new Category("Geography", "Questions about geography"); + return categoryService.getCategoryByName("Geography"); } } diff --git a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java index 860a5175..1bbd4475 100644 --- a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java @@ -1,6 +1,7 @@ package com.uniovi.components.generators.geography; import com.fasterxml.jackson.databind.JsonNode; +import com.uniovi.services.CategoryService; import java.util.*; @@ -8,7 +9,8 @@ public class BorderQuestionGenerator extends AbstractGeographyGenerator{ private Set usedCountries = new HashSet<>(); - public BorderQuestionGenerator() { + public BorderQuestionGenerator(CategoryService categoryService) { + super(categoryService); this.statement = "Which countries share a border with "; } diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index cda54a4a..4b0a3911 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -1,26 +1,29 @@ package com.uniovi.components.generators.geography; import com.fasterxml.jackson.databind.JsonNode; +import com.uniovi.services.CategoryService; + import java.util.ArrayList; import java.util.List; import java.util.Random; public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ - public CapitalQuestionGenerator() { + public CapitalQuestionGenerator(CategoryService categoryService) { + super(categoryService); this.statement = "What is the capital of "; } @Override public String getQuery() { return "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" + - "WHERE {\n" + - " ?country wdt:P31 wd:Q3624078 .\n" + - " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}\n" + - " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}\n" + - " OPTIONAL { ?country wdt:P36 ?capital } .\n" + - " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }\n" + - "}\n" + + "WHERE {" + + " ?country wdt:P31 wd:Q3624078 ." + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" + + " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" + + " OPTIONAL { ?country wdt:P36 ?capital } ." + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" + + "}" + "ORDER BY ?countryLabel"; } diff --git a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java index 8c81316e..6e89b66c 100644 --- a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java +++ b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java @@ -1,13 +1,15 @@ package com.uniovi.components.generators.geography; import com.fasterxml.jackson.databind.JsonNode; +import com.uniovi.services.CategoryService; import java.util.ArrayList; import java.util.List; import java.util.Random; public class ContinentQuestionGeneration extends AbstractGeographyGenerator{ - public ContinentQuestionGeneration() { + public ContinentQuestionGeneration(CategoryService categoryService) { + super(categoryService); this.statement = "In which continent is "; } diff --git a/src/main/java/com/uniovi/repositories/CategoryRepository.java b/src/main/java/com/uniovi/repositories/CategoryRepository.java index 8f9816bf..2771d22f 100644 --- a/src/main/java/com/uniovi/repositories/CategoryRepository.java +++ b/src/main/java/com/uniovi/repositories/CategoryRepository.java @@ -4,4 +4,7 @@ import org.springframework.data.repository.CrudRepository; public interface CategoryRepository extends CrudRepository { + + Category findByName(String name); + } diff --git a/src/main/java/com/uniovi/repositories/QuestionRepository.java b/src/main/java/com/uniovi/repositories/QuestionRepository.java index d7a05fac..d940deac 100644 --- a/src/main/java/com/uniovi/repositories/QuestionRepository.java +++ b/src/main/java/com/uniovi/repositories/QuestionRepository.java @@ -3,5 +3,7 @@ import com.uniovi.entities.Question; import org.springframework.data.repository.CrudRepository; +import java.util.Optional; + public interface QuestionRepository extends CrudRepository { } diff --git a/src/main/java/com/uniovi/services/CategoryService.java b/src/main/java/com/uniovi/services/CategoryService.java index 0972fa06..52f29eb7 100644 --- a/src/main/java/com/uniovi/services/CategoryService.java +++ b/src/main/java/com/uniovi/services/CategoryService.java @@ -32,4 +32,5 @@ public interface CategoryService { */ Optional getCategory(Long id); + Category getCategoryByName(String geography); } diff --git a/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java index ec4c45be..636bffe5 100644 --- a/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java @@ -3,11 +3,10 @@ import com.uniovi.entities.Category; import com.uniovi.repositories.CategoryRepository; import com.uniovi.services.CategoryService; +import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; @Service public class CategoryServiceImpl implements CategoryService { @@ -34,4 +33,23 @@ public List getAllCategories() { public Optional getCategory(Long id) { return categoryRepository.findById(id); } + + @Override + public Category getCategoryByName(String name) { + return categoryRepository.findByName(name); + } + + private static final Map.Entry[] CATEGORIES = new AbstractMap.SimpleEntry[] { + new AbstractMap.SimpleEntry<>("Geography", "Questions about geography") + }; + + @PostConstruct + public void init() { + // Add categories, ensuring there's only 1 of them always + for (Map.Entry category : CATEGORIES) { + if (categoryRepository.findByName(category.getKey())==null) { + addNewCategory(new Category(category.getKey(), category.getValue())); + } + } + } } diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java index 3cfaf4ce..0a3aa771 100644 --- a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java @@ -34,4 +34,5 @@ public List getAllQuestions() { public Optional getQuestion(Long id) { return questionRepository.findById(id); } + } From 19e1129eadc2bb932f4405ed581ef9c9fc1cc0c5 Mon Sep 17 00:00:00 2001 From: uo287545 Date: Thu, 29 Feb 2024 23:46:23 +0100 Subject: [PATCH 7/7] First version of the question generator ready --- ...rTest.java => QuestionGeneratorTestController.java} | 10 +++++----- .../generators/geography/CapitalQuestionGenerator.java | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) rename src/main/java/com/uniovi/components/{QuestionGeneratorTest.java => QuestionGeneratorTestController.java} (64%) diff --git a/src/main/java/com/uniovi/components/QuestionGeneratorTest.java b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java similarity index 64% rename from src/main/java/com/uniovi/components/QuestionGeneratorTest.java rename to src/main/java/com/uniovi/components/QuestionGeneratorTestController.java index cf549d65..82ba147e 100644 --- a/src/main/java/com/uniovi/components/QuestionGeneratorTest.java +++ b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java @@ -1,18 +1,18 @@ package com.uniovi.components; -import com.uniovi.components.generators.QuestionGenerator; +import com.uniovi.components.generators.geography.CapitalQuestionGenerator; import com.uniovi.entities.Question; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.List; -@Controller -public class QuestionGeneratorTest { +@RestController +public class QuestionGeneratorTestController { @Autowired - QuestionGenerator qgen; + CapitalQuestionGenerator qgen; @RequestMapping("/test") public void test() { diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index 4b0a3911..951292fc 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -2,11 +2,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.uniovi.services.CategoryService; +import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Random; +@Component public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ public CapitalQuestionGenerator(CategoryService categoryService) {