Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 단어 정보 & 감정 표현 관련 api 구현 #13

Merged
merged 29 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6383e6a
[feat] s3 config 작성
hysong4u Apr 17, 2024
0c5e93e
[feat] jsoup aws 의존성 추가
hysong4u Apr 17, 2024
06b365f
[feat] 수화 이미지 크롤링 컨트롤러 구현
hysong4u Apr 17, 2024
f04be3f
[feat] 수화 이미지 크롤링 메서드 구현
hysong4u Apr 17, 2024
1ad546e
[feat] 수화 이미지 크롤링 예외처리 구현
hysong4u Apr 17, 2024
9437828
[feat] gemini api 테스트
hysong4u Apr 18, 2024
016d7b5
[feat] 의존성 추가
hysong4u Apr 19, 2024
04e6bad
[feat] 수화카드 검색 api 구현
hysong4u Apr 19, 2024
aee5ba2
[fix] 생성형 ai 관련 코드 수정
hysong4u Apr 19, 2024
54b418e
[feat] 의존성 추가
hysong4u Apr 27, 2024
8676342
[feat] DALLE 단어카드 이미지 생성 구현
hysong4u Apr 27, 2024
2aff6c9
[feat] DALLE 단어카드 이미지 생성 API Dto 구현
hysong4u Apr 27, 2024
a9b9940
[fix] 단어인식 api 수정
hysong4u Apr 27, 2024
2d87793
[fix] dto 삭제
hysong4u Apr 27, 2024
3ddc9f6
[fix] 이미지 생성 api 수정
hysong4u Apr 27, 2024
eddbeae
[feat] gemini 수형 사진 상세 정보 추출 api controller 구현
hysong4u Apr 30, 2024
2bc593e
[feat] gemini 수형 사진 상세 정보 추출 api service 구현
hysong4u Apr 30, 2024
ccec501
[fix] 단어 저장 api request 이미지 추가
hysong4u Apr 30, 2024
75f6dff
[fix] 단어 검색 api 수정
hysong4u May 2, 2024
cee04c1
[fix] 단어 상세 검색 api Dto 구현
hysong4u May 2, 2024
c782b77
[fix] 사용자 카드 저장 api 변경
hysong4u May 2, 2024
7b5b6c4
[delete] 푸시알림 관련 기능 삭제
hysong4u May 2, 2024
655ebcd
[remove] 단어 인식으로 정보 조회 api 삭제
hysong4u May 2, 2024
b0543da
[fix] gemini 명령어 수정
hysong4u May 2, 2024
4428156
[feat] 내 단어 카드 조회 api 구현
hysong4u May 2, 2024
9f3326f
[feat] 감정표현 enum 구현
hysong4u May 2, 2024
20392d7
[feat] 감정표현 enum 구현
hysong4u May 2, 2024
dbed042
[feat] 감정표현 등록 및 조회 api dto 구현
hysong4u May 2, 2024
76320e9
[feat] 감정표현 등록 및 조회 api 구현
hysong4u May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ out/
.vscode/

application.yml
comma_firebase_key.json

16 changes: 14 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'


// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand All @@ -41,7 +42,6 @@ dependencies {
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'


//oauth2
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

Expand All @@ -55,7 +55,19 @@ dependencies {
//implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// aws
//implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.1'
implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.1'

//jsoup
implementation 'org.jsoup:jsoup:1.15.3'

//chatgpt
implementation 'io.github.flashvayne:chatgpt-spring-boot-starter:1.0.4'

//firebase
implementation 'com.google.firebase:firebase-admin:9.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'

implementation 'com.google.cloud:google-cloud-vertex-ai:1.2.0'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,77 @@
package com.example.comma.domain.card.controller;

import com.example.comma.domain.card.dto.request.CardInfoRequest;
import com.example.comma.domain.card.dto.response.*;
import com.example.comma.domain.card.service.CardService;
import com.example.comma.domain.external.service.GeminiService;
import com.example.comma.domain.external.service.ImageCrawlerService;
import com.example.comma.global.common.SuccessResponse;
import com.example.comma.global.config.auth.UserId;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

@RequiredArgsConstructor
@RequestMapping("/api/card")
@RestController
public class CardController {
private final CardService cardService;
private final GeminiService geminiService;
private final ImageCrawlerService imageCrawlerService;

@GetMapping("/{name}")
public ResponseEntity<SuccessResponse<?>> getWord(@PathVariable(name = "name") String name) {
CardImageResponseDto CardImage = cardService.getCardImage(name);
return SuccessResponse.ok(CardImage);

//단어 리스트 검색
@GetMapping("/search-word")
public ResponseEntity<SuccessResponse<?>> getSearchList(@RequestParam(name = "searchWord") String searchWord) throws IOException {
List<String> searchResults = imageCrawlerService.crawlSearchList(searchWord);
List<DescriptionResponseDto> descriptionResponse = geminiService.generateDescriptionList(searchResults);
return SuccessResponse.ok(descriptionResponse);
}

//단어 상세 정보 조회
@GetMapping("/search-details")
public ResponseEntity<SuccessResponse<?>> generateResponse(@RequestParam(name = "searchWord") String searchWord) throws IOException {

//수형, 단어 이미지 생성
List<String> signImageUrls = imageCrawlerService.crawlImageUrls(searchWord);
byte[] mergeImages = imageCrawlerService.mergeImages(signImageUrls);
String signImageUrl = imageCrawlerService.uploadFile(mergeImages, searchWord + ".jpg");
String generatedImageUrl = imageCrawlerService.generateImage(searchWord);;

//cardId 생성
cardService.registerCard(searchWord, signImageUrl);
Long cardId = cardService.getCardId(searchWord);

//단어 사전 정의 생성
List<DescriptionResponseDto> descriptionResponse = geminiService.generateDescriptionList(Collections.singletonList(searchWord));

//수형 동작 설명
String generatesignLanguageDescription= geminiService.generateSignDescription(searchWord);

WordDatailsResponseDto wordDatailsResponse = new WordDatailsResponseDto(cardId, searchWord, descriptionResponse.get(0).description(),descriptionResponse.get(0).partsOfSeech(), generatedImageUrl, signImageUrl,generatesignLanguageDescription );

return SuccessResponse.ok(wordDatailsResponse);
}


//UserCard 단어 카드 저장
@PostMapping("/{cardId}")
public ResponseEntity<SuccessResponse<?>> createCard(@UserId Long userId, @PathVariable(name = "cardId") Long cardId) {
cardService.createCard(userId, cardId);
public ResponseEntity<SuccessResponse<?>> saveCard(@UserId Long userId, @PathVariable(name = "cardId") Long cardId, @RequestBody CardInfoRequest cardInfoRequest) {
cardService.saveCard(userId, cardId, cardInfoRequest);
return SuccessResponse.created(null);
}

//UserCard 개별 정보 조회
@GetMapping("/my-card/{userCardId}")
public ResponseEntity<SuccessResponse<?>> getMyCard(@PathVariable(name = "userCardId") Long userCardId) {
MyCardResponseDto myCard = cardService.getMyCard(userCardId);
return SuccessResponse.ok(myCard);
}

@GetMapping("/lastest")
public ResponseEntity<SuccessResponse<?>> getLastestCard(@UserId Long userId) {
List<CardResponseDto> CardImage = cardService.getLatestCard(userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.comma.domain.card.dto.request;

public record CardInfoRequest(
String cardImageUrl,
String signLanguageDescription
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.comma.domain.card.dto.response;

public record DescriptionResponseDto(
String word,
String description,
String partsOfSeech
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.comma.domain.card.dto.response;

public record MyCardResponseDto(
String name,
String cardImageUrl,
String signImageUrl,
String signLanguageDescription
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.comma.domain.card.dto.response;

public record SearchCardResponseDto(
String generatedImageUrl,
String signImageUrl
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.comma.domain.card.dto.response;

public record WordDatailsResponseDto(
Long cardId,
String word,
String description,
String partsOfSeech,
String cardImageUrl,
String signImageUrl,
String signLanguageDescription

) {
}
10 changes: 6 additions & 4 deletions src/main/java/com/example/comma/domain/card/entity/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public class Card {

private String name;

private String CardImageUrl;

private String SignImageUrl;

private String signImageUrl;

@OneToMany(mappedBy = "card")
private List<UserCard> userCardList;

public Card(String name, String signImageUrl) {
this.name = name;
this.signImageUrl = signImageUrl;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ public class UserCard extends BaseTimeEntity {

private Boolean cardRegistration;

public UserCard(User user, Card card, Boolean quizParticipation, Boolean cardRegistration) {
private String cardImageUrl;
private String signLanguageDescription;

public UserCard(User user, Card card, Boolean quizParticipation, Boolean cardRegistration, String cardImageUrl, String signLanguageDescription) {
this.user = user;
this.card = card;
this.quizParticipation = quizParticipation;
this.cardRegistration = cardRegistration;
this.cardImageUrl = cardImageUrl;
this.signLanguageDescription = signLanguageDescription;
}

public void setQuizParticipation(Boolean quizParticipation) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.example.comma.domain.card.service;

import com.example.comma.domain.card.dto.response.CardImageResponseDto;
import com.example.comma.domain.card.dto.request.CardInfoRequest;
import com.example.comma.domain.card.dto.response.CardResponseDto;
import com.example.comma.domain.card.dto.response.CorrectCardResponseDto;
import com.example.comma.domain.card.dto.response.MyCardResponseDto;
import com.example.comma.domain.card.dto.response.WrongCardResponseDto;
import com.example.comma.domain.card.entity.Card;
import com.example.comma.domain.card.entity.UserCard;
import com.example.comma.domain.card.repository.CardRepository;
import com.example.comma.domain.card.repository.UserCardRepository;
import com.example.comma.domain.external.service.ImageCrawlerService;
import com.example.comma.domain.user.entity.User;
import com.example.comma.domain.user.repository.UserRepository;
import com.example.comma.global.error.ErrorCode;
Expand All @@ -20,6 +22,7 @@
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

Expand All @@ -32,17 +35,25 @@ public class CardService {
private final CardRepository cardRepository;
private final UserRepository userRepository;
private final UserCardRepository userCardRepository;
private final ImageCrawlerService imageCrawlerService;

public CardImageResponseDto getCardImage(String name) {
System.out.println("name = " + name);
public Long getCardId(String name) {
Card card = cardRepository.findByName(name)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.CARD_NOT_FOUND));
return new CardImageResponseDto(card.getId(), card.getCardImageUrl(), card.getSignImageUrl());
return card.getId();
}

public void registerCard(String name, String signImageUrl) {
Optional<Card> existingCardOptional = cardRepository.findByName(name);
if (existingCardOptional.isPresent()) {
return;
}
Card newCard = new Card(name, signImageUrl);
cardRepository.save(newCard);
}

public void createCard(Long userId, Long cardId) {

public void saveCard(Long userId, Long cardId, CardInfoRequest cardInfoRequest) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.USER_NOT_FOUND));

Expand All @@ -53,11 +64,12 @@ public void createCard(Long userId, Long cardId) {
throw new ConflictException(ErrorCode.USER_CARD_ALREADY_EXISTS);
}

UserCard userCard = new UserCard(user, card, false, true);
UserCard userCard = new UserCard(user, card, false, true, cardInfoRequest.cardImageUrl(), cardInfoRequest.signLanguageDescription());

userCardRepository.save(userCard);
}


@Transactional
@Scheduled(cron = "0 0 0 * * ?")
public void resetCardRegistration() {
Expand All @@ -82,7 +94,7 @@ private List<CardResponseDto> convertToCardResponseDtos(List<UserCard> userCards
return userCards.stream()
.map(userCard -> {
Card card = userCard.getCard();
return new CardResponseDto(userCard.getId(), card.getName(), card.getCardImageUrl(), card.getSignImageUrl());
return new CardResponseDto(userCard.getId(), card.getName(), userCard.getCardImageUrl(), card.getSignImageUrl());
})
.collect(Collectors.toList());
}
Expand All @@ -102,13 +114,12 @@ public CardResponseDto getCardDetail(Long userCardId) {
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.USER_CARD_NOT_FOUND));

Card card = userCard.getCard();
return new CardResponseDto(card.getId(), card.getName(), card.getCardImageUrl(), card.getSignImageUrl());
return new CardResponseDto(card.getId(), card.getName(), userCard.getCardImageUrl(), card.getSignImageUrl());
}

public WrongCardResponseDto getRandomQuizCard(Long userCardId) {
UserCard userCard = userCardRepository.findById(userCardId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.USER_CARD_NOT_FOUND));

List<UserCard> remainUserCards = userCardRepository.findUserCardByUserIdAndCardIdNot(userCard.getUser().getId(), userCardId);

if (remainUserCards.size() <= 1) {
Expand All @@ -125,7 +136,7 @@ public WrongCardResponseDto getRandomQuizCard(Long userCardId) {

randomCard = randomUserCard.getCard();

return new WrongCardResponseDto(randomCard.getName(), randomCard.getCardImageUrl(), randomCard.getSignImageUrl());
return new WrongCardResponseDto(randomCard.getName(), randomUserCard.getCardImageUrl(), randomCard.getSignImageUrl());
}


Expand All @@ -134,7 +145,7 @@ public CorrectCardResponseDto getQuizCard(Long userCardId) {
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.USER_CARD_NOT_FOUND));

Card card = userCard.getCard();
return new CorrectCardResponseDto(card.getName(), card.getCardImageUrl(), card.getSignImageUrl());
return new CorrectCardResponseDto(card.getName(), userCard.getCardImageUrl(), card.getSignImageUrl());
}

@Transactional
Expand All @@ -149,4 +160,12 @@ public List<CardResponseDto> getTop5Cards(Long userId) {
List<UserCard> userCards = userCardRepository.findTop5ByUserIdOrderByCreateDateDesc(userId);
return convertToCardResponseDtos(userCards);
}

public MyCardResponseDto getMyCard(Long userCardId) {
UserCard userCard = userCardRepository.findById(userCardId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.USER_CARD_NOT_FOUND));

Card card = userCard.getCard();
return new MyCardResponseDto(card.getName(), userCard.getCardImageUrl(),card.getSignImageUrl(), userCard.getSignLanguageDescription());
}
}
Loading
Loading