OpenAI 전사

OpenAI 전사 (Transcriptions)

Spring AI는 OpenAI의 Transcription 모델을 지원해요. 음성(오디오)을 텍스트로 변환하는 작업에 유용하죠. 이 글에서는 의존성 추가와 자동 설정, 전사 관련 프로퍼티, 런타임 옵션, 수동 구성, 그리고 diarized_json SDK 워크어라운드까지 다뤄볼게요.

출처: 문서

본문

Spring AI는 OpenAI’s Transcription model을 지원해요.

__ 2.0.0-M5 버전부터 Spring AI는 모든 OpenAI 모델을 위해 내부적으로 공식 openai-java SDK를 사용해요. 전환은 매끄러울 것으로 예상되며, OpenAI API 프로퍼티와 빌더의 기존 사용자에게는 호환성이 깨지는 변경이 없어요. 문제를 발견하면 Spring AI GitHub Issues로 알려주세요.

Prerequisites

ChatGPT 모델에 접근하려면 OpenAI로 API 키를 만들어야 해요. OpenAI signup page에서 계정을 만들고 API Keys page에서 토큰을 생성하세요. Spring AI 프로젝트는 spring.ai.openai.api-key라는 구성 프로퍼티를 정의하는데, 여기에 openai.com에서 얻은 API Key 값을 설정해야 해요. 환경 변수를 내보내는 것도 이 구성 프로퍼티를 설정하는 한 가지 방법이에요:

Auto-configuration

__ Spring AI 자동 설정과 스타터 모듈 아티팩트 이름에 큰 변경이 있었어요. 자세한 내용은 upgrade notes를 참고해주세요.

Spring AI는 OpenAI Transcription 클라이언트에 대한 Spring Boot 자동 설정을 제공해요. 활성화하려면 프로젝트의 Maven pom.xml 파일에 다음 의존성을 추가하세요:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

또는 Gradle build.gradle 빌드 파일에 추가할 수도 있어요:

dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}
__ 빌드 파일에 Spring AI BOM을 추가하려면 Dependency Management 섹션을 참고해주세요.

Transcription Properties

Connection Properties

프리픽스 spring.ai.openai는 OpenAI에 연결할 수 있게 해주는 프로퍼티 프리픽스예요.

Property Description Default
spring.ai.openai.base-url 연결할 URL api.openai.com
spring.ai.openai.api-key API 키 -
spring.ai.openai.organization-id 선택적으로 API 요청에 사용할 조직을 지정할 수 있어요. -
spring.ai.openai.project-id 선택적으로 API 요청에 사용할 프로젝트를 지정할 수 있어요. -
spring.ai.openai.timeout OpenAI 클라이언트의 요청 타임아웃. 60 sec.
spring.ai.openai.max-retries OpenAI 클라이언트의 최대 재시도 횟수. 3
spring.ai.openai.proxy OpenAI 클라이언트의 프록시 설정. -
spring.ai.openai.custom-headers OpenAI 클라이언트 요청에 추가할 커스텀 HTTP 헤더. empty
spring.ai.openai.connection-pool-metrics-enabled 기저 OkHttp 클라이언트의 연결 풀 메트릭을 활성화할지 여부. false
__ 여러 조직에 속한 사용자(또는 레거시 사용자 API 키로 프로젝트에 접근하는 사용자)의 경우, 선택적으로 API 요청에 사용할 조직과 프로젝트를 지정할 수 있어요. 이 API 요청의 사용량은 지정된 조직과 프로젝트의 사용량으로 집계돼요.

Configuration Properties

__ 오디오 전사 자동 설정의 활성화/비활성화는 이제 프리픽스 spring.ai.model.audio.transcription이 붙은 최상위 프로퍼티로 설정해요. 활성화하려면 spring.ai.model.audio.transcription=openai (기본값으로 활성화됨). 비활성화하려면 spring.ai.model.audio.transcription=none (또는 openai와 일치하지 않는 어떤 값). 이 변경은 여러 모델의 설정을 허용하기 위한 것이에요.

프리픽스 spring.ai.openai.audio.transcription은 OpenAI 전사 모델의 재시도 메커니즘을 구성할 수 있게 해주는 프로퍼티 프리픽스예요.

Property Description Default
spring.ai.model.audio.transcription OpenAI Audio Transcription Model 활성화 openai
spring.ai.openai.audio.transcription.base-url 연결할 URL api.openai.com
spring.ai.openai.audio.transcription.api-key API 키 -
spring.ai.openai.audio.transcription.organization-id 선택적으로 API 요청에 사용할 조직을 지정할 수 있어요. -
spring.ai.openai.audio.transcription.project-id 선택적으로 API 요청에 사용할 프로젝트를 지정할 수 있어요. -
spring.ai.openai.audio.transcription.model 전사에 사용할 모델의 ID. 사용 가능한 모델: gpt-4o-transcribe (GPT-4o 기반 음성-텍스트), gpt-4o-mini-transcribe (GPT-4o mini 기반 음성-텍스트), gpt-4o-transcribe-diarize (화자 분리), 또는 whisper-1 (범용 음성 인식 모델, 기본값). whisper-1
spring.ai.openai.audio.transcription.response-format 전사 출력의 형식: json, text, srt, verbose_json, vtt, 또는 diarized_json (화자 레이블이 있는 세그먼트, gpt-4o-transcribe-diarize 필요). text
spring.ai.openai.audio.transcription.prompt 모델의 스타일을 안내하거나 이전 오디오 세그먼트를 이어갈 선택적 텍스트. 프롬프트는 오디오 언어와 일치해야 해요.
spring.ai.openai.audio.transcription.language 입력 오디오의 언어. 입력 언어를 ISO-639-1 형식으로 제공하면 정확도와 지연 시간이 개선돼요.
spring.ai.openai.audio.transcription.temperature 샘플링 온도, 0에서 1 사이. 0.8 같은 높은 값은 출력을 더 무작위로 만들고, 0.2 같은 낮은 값은 더 집중적이고 결정적으로 만들죠. 0으로 설정하면 모델이 특정 임계값에 도달할 때까지 온도를 자동으로 높이기 위해 로그 확률을 사용해요. 0
spring.ai.openai.audio.transcription.timestamp-granularities 이 전사를 위해 채울 타임스탬프 세분성. timestamp granularities를 사용하려면 response_format이 verbose_json이어야 해요. word 또는 segment 중 하나 또는 둘 다 지원돼요. 참고: 세그먼트 타임스탬프에는 추가 지연이 없지만, 단어 타임스탬프 생성은 추가 지연이 발생해요. segment
spring.ai.openai.audio.transcription.known-speaker-names 화자 이름(최대 4개), known-speaker-references와 위치적으로 대응돼요. gpt-4o-transcribe-diarize에서만 사용돼요.
spring.ai.openai.audio.transcription.known-speaker-references 알려진 화자의 오디오 샘플(data URL 형태, 예: data:audio/wav;base64,…​), known-speaker-names와 위치적으로 대응돼요. gpt-4o-transcribe-diarize에서만 사용돼요.
spring.ai.openai.audio.transcription.chunking-strategy 오디오가 어떻게 청킹되는지 제어해요. 이 프로퍼티로는 auto만 지원돼요. voice-activity-detection 조정은 프로그래밍 방식으로 OpenAiAudioTranscriptionOptions.Builder를 사용하세요. whisper-1에서는 지원되지 않아요.
spring.ai.openai.audio.transcription.diarized-json-workaround-enabled diarized_json 응답을 잘못 분류하는 알려진 OpenAI Java SDK 버그(openai-java#802)를 우회할지 여부. diarized_json SDK Workaround 참고. true
__ 공통 spring.ai.openai.base-url, spring.ai.openai.api-key, spring.ai.openai.organization-id, spring.ai.openai.project-id 프로퍼티를 재정의할 수 있어요. spring.ai.openai.audio.transcription.base-url, spring.ai.openai.audio.transcription.api-key, spring.ai.openai.audio.transcription.organization-id, spring.ai.openai.audio.transcription.project-id 프로퍼티가 설정되면 공통 프로퍼티보다 우선해요. 서로 다른 모델과 서로 다른 모델 엔드포인트에 서로 다른 OpenAI 계정을 사용하려 할 때 유용해요.
__ spring.ai.openai.audio.transcription 프리픽스가 붙은 모든 프로퍼티는 런타임에 재정의할 수 있어요.

Runtime Options

OpenAiAudioTranscriptionOptions 클래스는 전사 요청을 할 때 사용할 옵션을 제공해요. 시작 시 spring.ai.openai.audio.transcription으로 지정한 옵션이 사용되지만 런타임에 이를 재정의할 수 있어요.

예:

OpenAiAudioTranscriptionOptions transcriptionOptions = OpenAiAudioTranscriptionOptions.builder()
    .language("en")
    .prompt("Ask not this, but ask that")
    .temperature(0f)
    .responseFormat(AudioResponseFormat.VTT)
    .build();
AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioFile, transcriptionOptions);
AudioTranscriptionResponse response = openAiTranscriptionModel.call(transcriptionRequest);

Response Metadata

verbose_json과 diarized_json의 경우, response.getMetadata()는 전사된 텍스트에 더해 getDuration(), getLanguage(), getUsage(), getSegments(), getWords()를 노출하는 OpenAiAudioTranscriptionResponseMetadata예요. 다른 응답 형식에서는 이 값들이 null/empty예요.

diarized_json SDK Workaround

OpenAI Java SDK(4.42.0 기준)는 diarized_json 응답을 잘못 분류해서, 그대로 두면 원시 JSON 페이로드가 전사 텍스트로 드러나요(openai-java#802). Spring AI는 이를 감지해 깨끗한 텍스트, 화자 세그먼트, 사용량을 자동으로 복구해요. 이 형식에서는 API가 duration을 반환하지 않으므로 duration은 계속 사용할 수 없어요. 워크어라운드를 비활성화하려면 OpenAiAudioTranscriptionOptions.Builder#diarizedJsonWorkaroundEnabled(false) 또는 spring.ai.openai.audio.transcription.diarized-json-workaround-enabled=false를 사용하세요.

Manual Configuration

프로젝트의 Maven pom.xml 파일에 spring-ai-openai 의존성을 추가하세요:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai</artifactId>
</dependency>

또는 Gradle build.gradle 빌드 파일에 추가할 수도 있어요:

dependencies {
    implementation 'org.springframework.ai:spring-ai-openai'
}
__ 빌드 파일에 Spring AI BOM을 추가하려면 Dependency Management 섹션을 참고해주세요.

다음으로 OpenAiAudioTranscriptionModel을 만들어볼게요:

var transcriptionOptions = OpenAiAudioTranscriptionOptions.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .responseFormat(AudioResponseFormat.TEXT)
    .temperature(0f)
    .build();

var openAiAudioTranscriptionModel = OpenAiAudioTranscriptionModel.builder()
    .options(transcriptionOptions)
    .build();

var audioFile = new FileSystemResource("/path/to/your/resource/speech/jfk.flac");

AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioFile, transcriptionOptions);
AudioTranscriptionResponse response = openAiAudioTranscriptionModel.call(transcriptionRequest);

Customizing the HTTP Client

Spring AI는 내부적으로 공식 openai-java SDK를 사용하며, SpringAiOpenAiHttpClient.Builder가 만든 커스텀 OkHttp 클라이언트로 HTTP 전송을 구성해요. 기저 OkHttpClient가 생성되기 전에 하나 이상의 OpenAiHttpClientBuilderCustomizer 빈을 노출해서 그 빌더를 가로챌 수 있어요. 각 커스터마이저는 모든 OpenAI 모델(chat, embedding, image, audio, moderation)이 사용하는 동일한 빌더를 받으므로, 커스터마이징이 균일하게 적용돼요.

@FunctionalInterface
public interface OpenAiHttpClientBuilderCustomizer {
    void customize(SpringAiOpenAiHttpClient.Builder builder);
}

전형적인 사용 사례:

  • OkHttp Interceptor 인스턴스 등록 (인증, 전파 헤더, 커스텀 로깅);

  • 디스패처 ExecutorService 교체 (예: 비동기 I/O를 가상 스레드로 라우팅);

  • 빌더가 노출하는 프록시, SSL, 호스트 이름 검증, 연결 풀 크기 구성.

커스터마이저가 여러 개 있으면 @Order / Ordered 순서로, Spring AI 기본값 이후에 적용되므로 사용자 코드가 우선해요.

OpenAi*Model.Builder를 통해 모델을 수동으로 연결할 때도 동일한 훅을 사용할 수 있어요:

var chatModel = OpenAiChatModel.builder()
    .options(OpenAiChatOptions.builder().model("gpt-4o").build())
    .httpClientBuilderCustomizer(myCustomizer)
    .build();

Example Code

더 알아보기 (Learn more)