이 포스팅은 kemi 라이브러리에 대한 설명을 담고 있습니다
지난 포스팅에 이어 0.2.1 버전에 대해 다룹니다
추가 기능 (0.2.1 기준)
- Image Generator 추가
- 이미지와 함께 질의응답
지원 버전
(0.1.0 과 동일합니다)
- JVM 8+
- Kotlin 1.9+
- Spring Boot 2.7+
- Spring 5.3+
라이브러리 설정
jitpack을 통해 배포되었습니다
아래와 같이 jitpack.io repository url 정의가 선행되어야 합니다
build.gradle.kts
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
dependencies {
implementation("com.github.hyuck0221:kemi:0.2.1")
}
application.yml
kemi:
gemini:
api-keys:
- your-first-api-key
- your-second-api-key
- your-third-api-key
base-url: https://generativelanguage.googleapis.com
models:
- gemini-2.5-flash
- gemini-2.5-flash-lite
- gemini-2.0-flash
- gemini-2.0-flash-lite
image-models: # NEW!
- gemini-2.5-flash-image
- gemini-3-pro-image-preview
- image-models (선택)
- Gemini 이미지 생성 AI Model
- 사용량 만료 시 다음 model로 자동 fallback
- 미입력 시 gemini-2.5-flash-image, gemini-3-pro-image-preview 적용
이미지 생성 사용법
Bean에 등록된 Generator를 불러와 호출합니다
import com.hshim.kemi.GeminiImageGenerator
import org.springframework.stereotype.Service
@Service
class ImageService(private val geminiImageGenerator: GeminiImageGenerator) {
fun generateImage() {
// 이미지 생성
val images = geminiImageGenerator.generateImage(
prompt = "산 위로 지는 아름다운 석양"
)
}
fun generateWithOptions() {
// 커스텀 종횡비와 해상도로 생성
val images = geminiImageGenerator.generateImage(
prompt = "밤의 미래 도시",
aspectRatio = "16:9",
imageSize = "4K"
)
}
fun generateWithReferenceImages() {
// 스타일 가이드를 위한 참조 이미지와 함께 생성
val referenceImage = ImageData.fromPath("style-reference.jpg")
val images = geminiImageGenerator.generateImage(
prompt = "이 예술적 스타일로 산 풍경을 그려주세요",
aspectRatio = "3:2",
imageSize = "2K",
referenceImages = listOf(referenceImage)
)
}
}
image-models에 설정된 모델로 이미지를 생성합니다
생성된 이미지는 Base64로 인코딩 된 형태로 전송받습니다
이미지 분석
기본 질의응답에 사용되는 GeminiGenerator와 채팅 형태의 GeminiChatGenerator에서 지원합니다 이미지 분석 및 이해를 위해 질문과 함께 이미지를 askWithImages 함수로 전송할 수 있습니다
import com.hshim.kemi.model.ImageData
@Service
class VisionService(
private val geminiGenerator: GeminiGenerator
) {
fun analyzeImage() {
// 파일에서 이미지 로드
val image = ImageData.fromPath("/path/to/photo.jpg")
val answer = geminiGenerator.askWithImages(
question = "이 이미지에 무엇이 있나요?",
images = listOf(image)
)
println(answer)
}
fun compareImages() {
// 여러 이미지를 한 번에 분석
val image1 = ImageData.fromFile(File("photo1.jpg"))
val image2 = ImageData.fromFile(File("photo2.png"))
val answer = geminiGenerator.askWithImages(
question = "이 두 이미지의 차이점은 무엇인가요?",
images = listOf(image1, image2)
)
println(answer)
}
}
채팅 대화에서 Vision 사용
@Service
class VisionChatService(
private val geminiChatGenerator: GeminiChatGenerator
) {
fun analyzeImagesInConversation() {
val chat = geminiChatGenerator.createSession()
// 이미지와 함께 첫 메시지
val image1 = ImageData.fromPath("diagram.png")
chat.sendMessageWithImages(
message = "이 다이어그램은 무엇을 보여주나요?",
images = listOf(image1)
)
// 후속 질문 (AI가 이미지 컨텍스트를 기억함)
chat.sendMessage("세 번째 구성 요소를 설명해 주실 수 있나요?")
// 같은 대화에서 다른 이미지
val image2 = ImageData.fromPath("chart.png")
chat.sendMessageWithImages(
message = "이 차트는 이전 다이어그램과 어떤 관련이 있나요?",
images = listOf(image2)
)
}
fun streamVisionResponse() {
val chat = geminiChatGenerator.createSession()
val image = ImageData.fromFile(File("complex-image.jpg"))
// 이미지 분석을 스트리밍 응답으로 받기
chat.sendMessageStreamWithImages(
message = "이 이미지를 자세히 설명해주세요",
images = listOf(image)
) { chunk ->
print(chunk) // 분석이 생성되는 대로 출력
}
}
}
마치며
개인 프로젝트를 진행하며 이미지 생성이 필요해저 지난번 설계한 kotlin + gemini 라이브러리에 적용 해 봤습니다
kemi 라이브러리의 목적이였던 ‘간단한 AI 호출’ 영역 내에서 이미지 생성까지 지원하게 되니 마음이 한결 편안하네요
이번에 gemini로 이미지 생성을 해보니 이미지 생성은 많이 비싸다는 걸 깨달았습니다
특히 pro 모델은 난발하지 마세요.. (많이 쓰지도 않았는데 금방 10$)
