diff --git a/build.gradle b/build.gradle index 6bef8bf..2977bf9 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,13 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-webflux' + implementation 'com.google.genai:google-genai:1.6.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' runtimeOnly 'com.mysql:mysql-connector-j' + } tasks.named('test') { diff --git a/src/main/java/com/kernellabs/kernellabs/application/GeminiService.java b/src/main/java/com/kernellabs/kernellabs/application/GeminiService.java new file mode 100644 index 0000000..e10234e --- /dev/null +++ b/src/main/java/com/kernellabs/kernellabs/application/GeminiService.java @@ -0,0 +1,46 @@ +package com.kernellabs.kernellabs.application; + +import autovalue.shaded.com.google.common.collect.ImmutableList; +import com.google.genai.Client; +import com.google.genai.types.GenerateContentConfig; +import com.google.genai.types.GenerateContentResponse; +import com.google.genai.types.GoogleSearch; +import com.google.genai.types.Tool; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class GeminiService { + + private final Client client; + private final Tool googleSearchTool; + private final String modelName; + + public GeminiService( + @Value("${gemini.api.key}") String apiKey, + @Value("${gemini.model:gemini-2.5-flash}") String modelName + ) { + this.client = Client.builder() + .apiKey(apiKey) + .build(); + + this.googleSearchTool = Tool.builder() + .googleSearch(GoogleSearch.builder().build()) + .build(); + + this.modelName = modelName; + } + + public String generateAnswer(String prompt) { + GenerateContentConfig config = GenerateContentConfig.builder() + .tools(ImmutableList.of(googleSearchTool)) + .build(); + + // ← 여기를 client.models()가 아니라 client.models 로 접근 + GenerateContentResponse res = client.models + .generateContent(modelName, prompt, config); + + return res.text(); + } + +} diff --git a/src/main/java/com/kernellabs/kernellabs/presentation/controller/GeminiController.java b/src/main/java/com/kernellabs/kernellabs/presentation/controller/GeminiController.java new file mode 100644 index 0000000..1ac63e8 --- /dev/null +++ b/src/main/java/com/kernellabs/kernellabs/presentation/controller/GeminiController.java @@ -0,0 +1,37 @@ +package com.kernellabs.kernellabs.presentation.controller; + +import com.kernellabs.kernellabs.application.GeminiService; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/genie") +@AllArgsConstructor +public class GeminiController { + private final GeminiService geminiService; + + @PostMapping("/chat") + public ResponseEntity chat(@Valid @RequestBody ChatRequest req) { + String answer = geminiService.generateAnswer(req.getPrompt()); + return ResponseEntity.ok(new ChatResponse(answer)); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ChatRequest { + private String prompt; + } + + @Data @NoArgsConstructor @AllArgsConstructor + public static class ChatResponse { + private String answer; + } +}