이 포스팅은 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$)