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

최종발표용 v2 배포 #405

Merged
merged 30 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ec1a7d1
feat: TT-486
ch8930 Oct 23, 2024
ed40ec5
feat: TT-486
ch8930 Oct 24, 2024
d583388
fix: TT-486
ch8930 Oct 28, 2024
2bc3cfd
fix: TT-499
ch8930 Nov 5, 2024
0a30644
Merge pull request #396 from twenty-three-23/faeture/TT-499
ch8930 Nov 6, 2024
ea0d907
fix: TT-486
ch8930 Nov 10, 2024
c3ca2b1
Merge branch 'dev' into feature/TT-486
ch8930 Nov 10, 2024
63b9988
fix: TT-486
ch8930 Nov 10, 2024
294b5ec
Merge remote-tracking branch 'origin/feature/TT-486' into feature/TT-486
ch8930 Nov 10, 2024
f8ee3fa
fix: TT-486
ch8930 Nov 10, 2024
d02bd0b
fix: TT-486
ch8930 Nov 10, 2024
1b23397
fix: TT-486
ch8930 Nov 10, 2024
ca89902
fix: TT-486
ch8930 Nov 10, 2024
a86b09b
Merge pull request #384 from twenty-three-23/feature/TT-486
ch8930 Nov 10, 2024
24d88e4
fix: TT-486
ch8930 Nov 10, 2024
38a7796
Merge pull request #397 from twenty-three-23/feature/TT-486
ch8930 Nov 11, 2024
6b31f55
fix: TT-486
ch8930 Nov 11, 2024
c13cfbf
Merge pull request #398 from twenty-three-23/feature/TT-486
ch8930 Nov 11, 2024
87ba028
fix: TT-486
ch8930 Nov 11, 2024
10ea2b7
Merge pull request #399 from twenty-three-23/feature/TT-486
ch8930 Nov 11, 2024
535abf9
fix: TT-486
ch8930 Nov 12, 2024
ef9c11f
Merge pull request #400 from twenty-three-23/feature/TT-486
ch8930 Nov 12, 2024
2e9fb61
bug: TT-486
ch8930 Nov 13, 2024
a511d66
Merge pull request #401 from twenty-three-23/feature/TT-486
ch8930 Nov 13, 2024
0f67314
bug: TT-486
ch8930 Nov 13, 2024
fd055a2
Merge pull request #402 from twenty-three-23/feature/TT-486
ch8930 Nov 13, 2024
3ec9a29
bug: TT-486
ch8930 Nov 13, 2024
7e50171
Merge pull request #403 from twenty-three-23/feature/TT-486
ch8930 Nov 13, 2024
123ea6b
bug: TT-486
ch8930 Nov 15, 2024
44537dd
Merge pull request #404 from twenty-three-23/feature/TT-486
ch8930 Nov 17, 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
13 changes: 13 additions & 0 deletions .github/workflows/cd_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
java-version: '17'
distribution: 'temurin'

- name: Set up GPT_PROMPT_SYSTEM environment variable decode
run: echo "GPT_PROMPT_SYSTEM=${{ secrets.GPT_PROMPT_SYSTEM }}" >> $GITHUB_ENV

- name: Set yaml file
uses: microsoft/variable-substitution@v1
with:
Expand All @@ -39,6 +42,7 @@ jobs:
logging.level.com.twentythree.peech: off
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY_PROD}}
gpt.prompt.system: ${{env.GPT_PROMPT_SYSTEM}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
Expand All @@ -55,6 +59,9 @@ jobs:
ffmpeg.path: ${{ secrets.FFMPEG_PATH_PROD }}
ffprobe.path: ${{ secrets.FFPROBE_PATH_PROD }}
spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS_PROD }}
fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }}
fcm.key-path: ${{ secrets.FCM_KEY_PATH }}
fcm.project-id: ${{ secrets.FCM_PROJECT_ID }}
meta.api-version: ${{ secrets.META_API_VERSION}}
meta.web.pixel-id: ${{ secrets.META_WEB_PIXEL_ID_PROD}}
meta.web.access-token: ${{ secrets.META_WEB_ACCESS_TOKEN_PROD}}
Expand All @@ -71,6 +78,12 @@ jobs:
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew

# fcm 서버 키 설정
- name: Set up FCM server key
run: |
cd ./src/main/resources/
echo "${{ secrets.FCM_SECRET_KEY }}" | base64 --decode > ./peech_fcm.json

# 2. Spring Boot 애플리케이션 빌드
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/ci_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
java-version: '17'
distribution: 'temurin'

- name: Set up GPT_PROMPT_SYSTEM environment variable decode
run: echo "GPT_PROMPT_SYSTEM=${{ secrets.GPT_PROMPT_SYSTEM }}" >> $GITHUB_ENV

- name: Set yaml file
uses: microsoft/variable-substitution@v1
with:
Expand All @@ -39,6 +42,7 @@ jobs:
logging.level.com.twentythree.peech: off
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY_PROD}}
gpt.prompt.system: ${{env.GPT_PROMPT_SYSTEM}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
Expand All @@ -55,6 +59,9 @@ jobs:
ffmpeg.path: ${{ secrets.FFMPEG_PATH_PROD }}
ffprobe.path: ${{ secrets.FFPROBE_PATH_PROD }}
spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS_PROD }}
fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }}
fcm.key-path: ${{ secrets.FCM_KEY_PATH }}
fcm.project-id: ${{ secrets.FCM_PROJECT_ID }}
meta.api-version: ${{ secrets.META_API_VERSION}}
meta.web.pixel-id: ${{ secrets.META_WEB_PIXEL_ID_PROD}}
meta.web.access-token: ${{ secrets.META_WEB_ACCESS_TOKEN_PROD}}
Expand All @@ -70,6 +77,12 @@ jobs:
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew

# fcm 서버 키 설정
- name: Set up FCM server key
run: |
cd ./src/main/resources/
echo "${{ secrets.FCM_SECRET_KEY }}" | base64 --decode > ./peech_fcm.json

# 2. Spring Boot 애플리케이션 빌드
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
Expand Down
15 changes: 14 additions & 1 deletion .github/workflows/cicd_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ jobs:
with:
java-version: '17'
distribution: 'temurin'


- name: Set up GPT_PROMPT_SYSTEM environment variable decode
run: echo "GPT_PROMPT_SYSTEM=${{ secrets.GPT_PROMPT_SYSTEM }}" >> $GITHUB_ENV

- name: Set yaml file
uses: microsoft/variable-substitution@v1
with:
Expand All @@ -40,6 +43,7 @@ jobs:
logging.level.com.twentythree.peech: off
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY}}
gpt.prompt.system: ${{env.GPT_PROMPT_SYSTEM}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
Expand All @@ -56,6 +60,9 @@ jobs:
ffmpeg.path: ${{ secrets.FFMPEG_PATH_DEV }}
ffprobe.path: ${{ secrets.FFPROBE_PATH_DEV }}
spring.cors.allowed-origins: ${{ secrets.CORS_ALLOWED_ORIGINS }}
fcm.secret-key: ${{ secrets.FCM_SECRET_KEY }}
fcm.key-path: ${{ secrets.FCM_KEY_PATH }}
fcm.project-id: ${{ secrets.FCM_PROJECT_ID }}
meta.api-version: ${{ secrets.META_API_VERSION}}
meta.web.pixel-id: ${{ secrets.META_WEB_PIXEL_ID}}
meta.web.access-token: ${{ secrets.META_WEB_ACCESS_TOKEN}}
Expand All @@ -70,6 +77,12 @@ jobs:
# excute 허용
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew

# fcm 서버 키 설정
- name: Set up FCM server key
run: |
cd ./src/main/resources/
echo "${{ secrets.FCM_SECRET_KEY }}" | base64 --decode > ./peech_fcm.json

# 2. Spring Boot 애플리케이션 빌드
- name: Build with Gradle
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ data.sql

### Logging File ###
/logs/**

### FCM Admin SDK ###
**/src/main/resources/peech_fcm.json
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ dependencies {
// ffmpeg
implementation 'net.bramp.ffmpeg:ffmpeg:0.8.0'

//firebase sdk
implementation 'com.google.firebase:firebase-admin:9.3.0'

//thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/twentythree/peech/PeechApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableJpaAuditing
@SpringBootApplication
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.twentythree.peech.analyzescript.application;

import com.twentythree.peech.analyzescript.domain.AnalyzeScriptPredictor;
import com.twentythree.peech.fcm.application.NotificationService;
import com.twentythree.peech.script.service.ScriptService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class AnalyzeScriptFacade {

private final AnalyzeScriptPredictor analyzeScriptPredictor;
private final ScriptService scriptService;
private final NotificationService notificationService;
private final Logger log = LoggerFactory.getLogger(this.getClass());

@Async
public void analyzeScriptAndSave(Long userId, Long scriptId, String scriptContent) {
analyzeScriptPredictor.requestAnalyzeScript(scriptContent)
.thenAccept(result -> {
scriptService.reflectAnalyzeResult(scriptId, result);
notificationService.pushNotification(userId);
})
.exceptionally(e -> {
log.error("스크립트 분석 중 예외 발생", e);
return null;
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.twentythree.peech.analyzescript.client;

import com.twentythree.peech.analyzescript.dto.request.GPTRequest;
import com.twentythree.peech.common.dto.response.GPTResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient(
name = "analyzeScriptGPT",
url = "https://api.openai.com/")
public interface AnalyzeScriptGPT {

@PostMapping("v1/chat/completions")
GPTResponse analyzeScript(GPTRequest gptRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.twentythree.peech.analyzescript.domain;

import com.twentythree.peech.analyzescript.client.AnalyzeScriptGPT;
import com.twentythree.peech.analyzescript.dto.request.GPTRequest;
import com.twentythree.peech.common.dto.Message;
import com.twentythree.peech.common.dto.response.GPTResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Async
@RequiredArgsConstructor
@Component
public class AnalyzeScriptPredictor {

@Value("${gpt.prompt.system}")
private String gptSystemPrompt;

private final AnalyzeScriptGPT analyzeScriptGPT;

public CompletableFuture<String> requestAnalyzeScript(String scriptContent) {
List<Message> messages = new ArrayList<>();

String systemPrompt = gptSystemPrompt;
messages.add(new Message("system", systemPrompt));

String userPrompt = "자기소개서: " + scriptContent;

messages.add(new Message("user", userPrompt));

GPTRequest gptRequest = new GPTRequest("gpt-4o-mini", messages);
GPTResponse gptResponse = analyzeScriptGPT.analyzeScript(gptRequest);
String result = gptResponse.getChoices().get(0).getMessage().getContent();

return CompletableFuture.completedFuture(result);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.twentythree.peech.analyzescript.dto.request;

import com.twentythree.peech.common.dto.Message;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@Getter
@AllArgsConstructor
public class GPTRequest {
private String model;
private List<Message> messages;
}
24 changes: 24 additions & 0 deletions src/main/java/com/twentythree/peech/config/async/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.twentythree.peech.config.async;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 기본 스레드 수
executor.setMaxPoolSize(30); // 최대 스레드 수
executor.setQueueCapacity(50); // 작업 대기 큐 크기
executor.setThreadNamePrefix("AsyncExecutor-");
executor.initialize();
return executor;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.twentythree.peech.fcm.application;

import com.twentythree.peech.fcm.dto.request.RequestFCMTokenDTO;

public interface NotificationService {
void pushNotification(Long userId);
void saveOrUpdateToken(RequestFCMTokenDTO fcmTokenDTO, Long userId);
void testPushNotification(Long userId);
void deleteToken(String deviceId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.twentythree.peech.fcm.application;


import com.twentythree.peech.fcm.dto.request.RequestFCMTokenDTO;
import com.twentythree.peech.fcm.entity.NotificationEntity;
import com.twentythree.peech.fcm.event.FCMPushedEvent;
import com.twentythree.peech.fcm.event.FCMTestPushEvent;
import com.twentythree.peech.fcm.infra.NotificationRepository;
import com.twentythree.peech.user.entity.UserEntity;
import com.twentythree.peech.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@RequiredArgsConstructor
@Service
public class NotificationServiceImpl implements NotificationService {

private final NotificationRepository notificationRepository;
private final UserRepository userRepository;
private final ApplicationEventPublisher applicationEventPublisher;

public void pushNotification(Long userId) {
List<String> fcmTokenList = notificationRepository.findAllByUserId(userId);

if(fcmTokenList.isEmpty()){
throw new IllegalStateException("FCM 토큰이 존재하지 않습니다.");
}

applicationEventPublisher.publishEvent(new FCMPushedEvent(fcmTokenList));
}

@Transactional
@Override
public void saveOrUpdateToken(RequestFCMTokenDTO request, Long userId) {
notificationRepository.findByDeviceId(request.getDeviceId())
.ifPresentOrElse(
fcmToken -> updateFCMToken(fcmToken, request.getFcmToken()),

() -> {
UserEntity userEntity = userRepository.findById(userId)
.orElseThrow(() -> new IllegalStateException("유저가 존재하지 않습니다."));
NotificationEntity newEntity = NotificationEntity
.ofCreateFCMToken(
userEntity,
request.getDeviceId(),
request.getFcmToken()
);
notificationRepository.save(newEntity);
});
}

@Override
public void testPushNotification(Long userId) {
List<String> fcmTokenList = notificationRepository.findAllByUserId(userId);

if(fcmTokenList.isEmpty()){
throw new IllegalStateException("FCM 토큰이 존재하지 않습니다.");
}

applicationEventPublisher.publishEvent(new FCMTestPushEvent(fcmTokenList));
}

@Override
public void deleteToken(String deviceId) {
notificationRepository.findByDeviceId(deviceId)
.ifPresentOrElse(
notificationRepository::delete,
() -> { throw new IllegalStateException("deviceId가 존재하지 않습니다.");}
);
}

private void updateFCMToken(NotificationEntity originEntity, String newToken){
originEntity.updateToken(newToken);
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/twentythree/peech/fcm/client/FCMClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.twentythree.peech.fcm.client;


import com.google.firebase.messaging.FirebaseMessaging;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient(
name = "FCMClient",
url = "https://fcm.googleapis.com/v1/projects/${fcm.project-id}/messages:send"
)
public interface FCMClient {

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
void sendNotification(
FirebaseMessaging message
);


}
Loading
Loading