Skip to content

Commit

Permalink
Merge pull request #45 from Princess-in-silvertown/feat/43
Browse files Browse the repository at this point in the history
Feat: ν‚€μ›Œλ“œ μžλ™ 생성 κΈ°λŠ₯
  • Loading branch information
loveysuby authored Sep 7, 2024
2 parents b81e191 + 66c7795 commit 33517bf
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 5 deletions.
6 changes: 2 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,17 @@ repositories {
}

dependencies {
// Spring Boot μ„€μ •
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
developmentOnly 'org.springframework.boot:spring-boot-devtools'

// λ°μ΄ν„°λ² μ΄μŠ€ μ˜μ‘΄μ„± μ„€μ •
implementation 'org.springframework.boot:spring-boot-starter-webflux'

runtimeOnly 'com.h2database:h2'

// Lombok μ„€μ •
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// ν…ŒμŠ€νŠΈ ν™˜κ²½ μ„€μ •
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/slvtwn/khu/toyouserver/agent/gpt/ChatGptAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package slvtwn.khu.toyouserver.agent.gpt;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@AllArgsConstructor
@Component
public class ChatGptAgent {

private ChatGptConfiguration configuration;

public ChatGptResponse requestWithPrompt(String prompt) {
HashMap<String, Object> body = setupBody(prompt);

return WebClient.create()
.post()
.uri(configuration.getTextModel())
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + configuration.getOpenaiKey())
.bodyValue(body)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError,
clientResponse -> clientResponse.bodyToMono(String.class).map(Exception::new))
.bodyToMono(ChatGptResponse.class)
.block();
}


private HashMap<String, Object> setupBody(String prompt) {
HashMap<String, Object> body = new HashMap<>();
body.put("model", configuration.getTextModel());

HashMap<String, String> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", prompt);

List<HashMap<String, String>> messages = new ArrayList<>();
messages.add(userMessage);
body.put("messages", messages);
return body;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package slvtwn.khu.toyouserver.agent.gpt;

import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Getter
@Component
public class ChatGptConfiguration {

@Value("${openai.key}")
private String openaiKey;
@Value("${openai.text-generation.endpoint}")
private String textModelEndpoint;
@Value("${openai.text-generation.model}")
private String textModel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package slvtwn.khu.toyouserver.agent.gpt;

import java.util.List;

public record ChatGptResponse(String id, String object, Long created, List<Choice> choices, Usage usage) {

public record Choice(
String text,
int index,
String logprobs,
String finish_reason
) {
}

public record Usage(
int prompt_tokens,
int completion_tokens,
int total_tokens
) {
}
}
62 changes: 62 additions & 0 deletions src/main/java/slvtwn/khu/toyouserver/application/AgentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package slvtwn.khu.toyouserver.application;

import java.util.Arrays;
import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import slvtwn.khu.toyouserver.agent.gpt.ChatGptAgent;
import slvtwn.khu.toyouserver.agent.gpt.ChatGptResponse;
import slvtwn.khu.toyouserver.dto.KeywordRequest;
import slvtwn.khu.toyouserver.dto.KeywordResponse;

@AllArgsConstructor
@Service
public class AgentService {

private final ChatGptAgent chatGptAgent;

public KeywordResponse generateKeywords(KeywordRequest request) {
String content = request.content();
String prompt = String.format("""
Suggest 3 keywords that could represent emotions or characteristics in the content.
<example>
<request>
content:
μ•ˆλ…•, μ €λ²ˆ 학기에 λ§Œλ‚˜μ„œ 정말 λ°˜κ°€μ› μ–΄! μ•žμœΌλ‘œ 또 λ§Œλ‚  수 μžˆμ„κ±°λΌ κΈ°λŒ€ν•˜κ³  μžˆμ–΄.
정말 μ•„μ‰½μ§€λ§Œ κ±΄κ°•ν•˜κ²Œ 잘 지내!
keywords:
</request>
<response>
λ°˜κ°€μ›€, κΈ°λŒ€, 아쉬움
</response>
</example>
<example>
<request>
content:
생일 μΆ•ν•˜ν•΄! 생일 μΆ•ν•˜ νŒŒν‹°μ— 직접 μ°Έμ—¬ν•˜μ§„ λͺ»ν•΄μ„œ μ•„μ‰½μ§€λ§Œ, 즐겁게 ν•˜λ£¨λ₯Ό λ³΄λƒˆμœΌλ©΄ μ’‹κ² μ–΄.
keywords:
</request>
<response>
μΆ•ν•˜, 아쉬움, 즐거움
</response>
</example>
content: %s
keywords:
""", content);

ChatGptResponse chatGptResponse = chatGptAgent.requestWithPrompt(prompt);
ChatGptResponse.Choice firstChoice = chatGptResponse.choices().get(0);
List<String> keywords = parseKeywordFromChoice(firstChoice);

return new KeywordResponse(keywords);
}

private List<String> parseKeywordFromChoice(ChatGptResponse.Choice choice) {
String text = choice.text();
return Arrays.stream(text.split(","))
.toList();
}
}
5 changes: 5 additions & 0 deletions src/main/java/slvtwn/khu/toyouserver/dto/KeywordRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package slvtwn.khu.toyouserver.dto;

public record KeywordRequest(String content) {

}
7 changes: 7 additions & 0 deletions src/main/java/slvtwn/khu/toyouserver/dto/KeywordResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package slvtwn.khu.toyouserver.dto;

import java.util.List;

public record KeywordResponse(List<String> keywords) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package slvtwn.khu.toyouserver.presentation;

import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import slvtwn.khu.toyouserver.application.AgentService;
import slvtwn.khu.toyouserver.common.response.ToyouResponse;
import slvtwn.khu.toyouserver.dto.KeywordRequest;
import slvtwn.khu.toyouserver.dto.KeywordResponse;

@AllArgsConstructor
@RestController
public class AgentController {

private final AgentService agentService;

@PostMapping("/generate-keywords")
public ToyouResponse<KeywordResponse> generateKeywords(@RequestBody KeywordRequest keywordRequest) {
KeywordResponse response = agentService.generateKeywords(keywordRequest);
return ToyouResponse.from(response);
}
}
7 changes: 6 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
spring:
jpa:
# database: mysql
open-in-view: false
generate-ddl: true
show-sql: true
Expand All @@ -14,3 +13,9 @@ spring:
username: sa
password:

openai:
key: ${OPEN_AI_KEY}

text-generation:
endpoint: https://api.openai.com/v1/chat/completions
model: gpt-4o-mini
21 changes: 21 additions & 0 deletions src/test/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
spring:
jpa:
open-in-view: false
generate-ddl: true
show-sql: true
properties:
hibernate:
format_sql: true

datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:

openai:
key: test-key

text-generation:
endpoint: https://api.openai.com/v1/chat/completions
model: gpt-4o-mini

0 comments on commit 33517bf

Please sign in to comment.