<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>yoozafree 님의 블로그</title>
    <link>https://yoozafree.tistory.com/</link>
    <description>진인사대천명</description>
    <language>ko</language>
    <pubDate>Sat, 8 Aug 2026 07:48:19 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>yoozafree</managingEditor>
    <image>
      <title>yoozafree 님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/8420085/attach/460e3aebe48747a885ba34d36f70a98d</url>
      <link>https://yoozafree.tistory.com</link>
    </image>
    <item>
      <title>회의 녹음에서 할 일을 자동 생성하기: Deepgram 화자 분리 기반 STT 적용기 및 OpenAI 프롬프팅</title>
      <link>https://yoozafree.tistory.com/2</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tJ9kW/dJMcahdtYoA/sIETkPlvQT0x7xTOnPG2C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tJ9kW/dJMcahdtYoA/sIETkPlvQT0x7xTOnPG2C1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tJ9kW/dJMcahdtYoA/sIETkPlvQT0x7xTOnPG2C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtJ9kW%2FdJMcahdtYoA%2FsIETkPlvQT0x7xTOnPG2C1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;512&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;Whisper에서 Deepgram으로 전환하며 회의 참석자별 발화를 구분하고, 이를 기반으로 의 할 일 자동 생성 흐름을 설계한 과정&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7a1c06c2-8347-40a3-a748-c2dae260c833.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XXn4V/dJMcafUhuOg/WqBgMKLrVNZZo9UQQFhfSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XXn4V/dJMcafUhuOg/WqBgMKLrVNZZo9UQQFhfSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XXn4V/dJMcafUhuOg/WqBgMKLrVNZZo9UQQFhfSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXXn4V%2FdJMcafUhuOg%2FWqBgMKLrVNZZo9UQQFhfSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;1024&quot; data-filename=&quot;7a1c06c2-8347-40a3-a748-c2dae260c833.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 서비스는 회의 녹음 파일을 기반으로 회의 내용을 기록하고, 회의 중 언급된 할 일을 자동으로 추출해주는 회의 기록 서비스다. &lt;br /&gt;&lt;br /&gt;회의가&amp;nbsp;끝난&amp;nbsp;뒤&amp;nbsp;사용자는&amp;nbsp;&amp;ldquo;누가&amp;nbsp;어떤&amp;nbsp;일을&amp;nbsp;하기로&amp;nbsp;했는지&amp;rdquo;&amp;nbsp;다시&amp;nbsp;정리해야&amp;nbsp;하는&amp;nbsp;번거로움을&amp;nbsp;겪는다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;우리는 이 과정을 줄이기 위해 음성 파일을 텍스트로 변환하고, 변환된 회의록을 기반으로 Action Item을 자동 생성하는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 초기에는 OpenAI Whisper를 사용해 회의 녹음 파일을 텍스트로 변환했다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;Whisper는 음성을 텍스트로 변환하는 데는 적합했지만, 회의 서비스에서 중요한 &amp;ldquo;누가 말했는지&amp;rdquo;를 구분하는 것, 즉 화자 분리를 적용하는 데 한계가 있었다. &lt;br /&gt;&lt;br /&gt;우리 서비스에서 필요한 것은 단순한 전체 회의록이 아니라, 다음과 같은 형태의 데이터였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779684334731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예시
화자 0: 오늘까지 포스터 수정해볼게요.
화자 1: 저는 발표 자료 정리하겠습니다.
화자 0: 그럼 내일까지 최종본 공유할게요.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 발화자가 구분되어야 이후 LLM이 &amp;ldquo;누가 어떤 일을 맡았는지&amp;rdquo; 더 정확하게 추출할 수 있다. &lt;br /&gt;&lt;br /&gt;따라서 STT 도구를 Whisper에서 Deepgram으로 변경했고, Deepgram의 diarization 기능을 활용해 화자 분리가 포함된 회의록을 생성하도록 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 서비스 처리 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779684470547&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[회의 녹음 파일 업로드]
        &amp;darr;
[Deepgram STT 요청]
        &amp;darr;
[화자 분리 diarization]
        &amp;darr;
[화자별 회의록 문자열 변환]
        &amp;darr;
[LLM에게 Action Item 추출 요청]
        &amp;darr;
[할 일 목록 생성]
        &amp;darr;
[KNOTE 화면에 표시]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Deepgram Service 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779684538757&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DeepgramService.java

@Slf4j
@Service
public class DeepgramService {

  @Value(&quot;${deepgram.api.key}&quot;)
  private String apiKey;

  @Value(&quot;${deepgram.api.url}&quot;)
  private String apiUrl;

  private final RestTemplate restTemplate;

  public DeepgramService() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(60000);
    factory.setReadTimeout(120000);
    this.restTemplate = new RestTemplate(factory);
  }

  public String transcribeWithDiarization(byte[] fileBytes) {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.parseMediaType(&quot;audio/wav&quot;));
    headers.set(&quot;Authorization&quot;, &quot;Token &quot; + apiKey);

    String url = apiUrl
        + &quot;?model=nova-2&amp;amp;smart_format=true&amp;amp;diarize=true&amp;amp;language=ko&quot;;

    HttpEntity&amp;lt;byte[]&amp;gt; requestEntity = new HttpEntity&amp;lt;&amp;gt;(fileBytes, headers);

    try {
      ResponseEntity&amp;lt;Map&amp;gt; response =
          restTemplate.postForEntity(url, requestEntity, Map.class);

      return formatDeepgramResult(response.getBody());
    } catch (Exception e) {
      log.error(&quot;Deepgram API 호출 실패&quot;, e);
      throw new RuntimeException(&quot;화자 분리 처리 중 오류 발생&quot;);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이어서 아래의 부분에서 코드 설명을 진행하겠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 설명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DeepgramService는 회의 녹음 파일을 받아 Deepgram API에 전달하고, 응답 결과를 KNOTE에서 사용하기 쉬운 문자열 형태로 변환하는 역할을 한다. &lt;br /&gt;&lt;br /&gt;핵심 옵션은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-end=&quot;3264&quot; data-start=&quot;3098&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;3152&quot; data-start=&quot;3120&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;3137&quot; data-start=&quot;3120&quot;&gt;model=nova-2&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-end=&quot;3152&quot; data-start=&quot;3137&quot; data-col-size=&quot;sm&quot;&gt;음성 인식 모델 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;3200&quot; data-start=&quot;3153&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;3175&quot; data-start=&quot;3153&quot;&gt;smart_format=true&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-end=&quot;3200&quot; data-start=&quot;3175&quot; data-col-size=&quot;sm&quot;&gt;문장 부호, 숫자 등 텍스트 형식 개선&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;3231&quot; data-start=&quot;3201&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;3218&quot; data-start=&quot;3201&quot;&gt;diarize=true&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-end=&quot;3231&quot; data-start=&quot;3218&quot; data-col-size=&quot;sm&quot;&gt;화자 분리 활성화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;3264&quot; data-start=&quot;3232&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;3248&quot; data-start=&quot;3232&quot;&gt;language=ko&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-end=&quot;3264&quot; data-start=&quot;3248&quot; data-col-size=&quot;sm&quot;&gt;한국어 회의 녹음 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 &lt;b&gt;diarize=true&lt;/b&gt; 옵션이 가장 중요하다. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;이 옵션을 통해 Deepgram은 발화 구간마다 speaker 값을 부여하고, KNOTE는 이를 이용해 &amp;ldquo;화자 0&amp;rdquo;, &amp;ldquo;화자 1&amp;rdquo; 형태의 회의록을 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스에 회의 녹음 파일을 업로드하면 먼저 회의 정보를 DB에 저장한다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;이후&amp;nbsp;업로드된&amp;nbsp;파일을&amp;nbsp;byte&amp;nbsp;배열로&amp;nbsp;복사한&amp;nbsp;뒤,&amp;nbsp;별도의&amp;nbsp;AI&amp;nbsp;처리&amp;nbsp;로직으로&amp;nbsp;전달한다. &lt;br /&gt;&lt;br /&gt;파일&amp;nbsp;업로드&amp;nbsp;직후&amp;nbsp;바로&amp;nbsp;분석&amp;nbsp;결과를&amp;nbsp;기다리게&amp;nbsp;하면&amp;nbsp;사용자는&amp;nbsp;긴&amp;nbsp;시간&amp;nbsp;동안&amp;nbsp;응답을&amp;nbsp;기다려야&amp;nbsp;한다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;따라서&amp;nbsp;회의는&amp;nbsp;먼저&amp;nbsp;`PENDING`&amp;nbsp;상태로&amp;nbsp;생성하고,&amp;nbsp;STT와&amp;nbsp;요약,&amp;nbsp;Action&amp;nbsp;Item&amp;nbsp;생성은&amp;nbsp;별도&amp;nbsp;처리&amp;nbsp;흐름에서&amp;nbsp;진행되도록&amp;nbsp;구성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685368025&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(value = &quot;/record-file&quot;, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity&amp;lt;CreateMeetingRecordResponse&amp;gt; createMeetingByFile(
    @RequestPart(&quot;file&quot;) MultipartFile file,
    @ModelAttribute @Valid CreateMeetingRecordRequest request
) {
  return ResponseEntity.status(HttpStatus.CREATED)
      .body(meetingService.createMeetingByFile(file, request));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 AI 분석은 &lt;b&gt;processAiTasks()&lt;/b&gt; 메서드에서 진행된다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;이&amp;nbsp;메서드는&amp;nbsp;하나의&amp;nbsp;회의&amp;nbsp;ID와&amp;nbsp;녹음&amp;nbsp;파일&amp;nbsp;byte&amp;nbsp;배열을&amp;nbsp;받아&amp;nbsp;다음&amp;nbsp;순서로&amp;nbsp;동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685405172&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;회의 조회
&amp;darr;
Deepgram STT 실행
&amp;darr;
화자별 회의록 저장
&amp;darr;
OpenAI 요약/분석 요청
&amp;darr;
AI 응답 JSON 파싱
&amp;darr;
회의 요약 저장
&amp;darr;
Action Item 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685418232&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String transcript = deepgramService.transcribeWithDiarization(fileBytes);

meeting.setTranscript(transcript);
meeting.setStatus(&quot;PROCESSING&quot;);
meetingRepository.saveAndFlush(meeting);

String aiJsonResponse = openAiService.summarize(transcript);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deepgram을 통해 생성된 transcript는 Meeting 엔티티의 &lt;b&gt;transcript&lt;/b&gt; 필드에 저장된다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;이후&amp;nbsp;해당&amp;nbsp;transcript를&amp;nbsp;OpenAI&amp;nbsp;요약&amp;nbsp;로직에&amp;nbsp;전달하여&amp;nbsp;회의&amp;nbsp;요약과&amp;nbsp;Action&amp;nbsp;Item을&amp;nbsp;생성한다. &lt;br /&gt;&lt;br /&gt;즉,&amp;nbsp;Deepgram은&amp;nbsp;음성을&amp;nbsp;텍스트로&amp;nbsp;변환하는&amp;nbsp;역할을&amp;nbsp;하고,&amp;nbsp;OpenAI는&amp;nbsp;텍스트에서&amp;nbsp;의미&amp;nbsp;있는&amp;nbsp;회의&amp;nbsp;결과를&amp;nbsp;추출하는&amp;nbsp;역할을&amp;nbsp;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; AI 응답에서 Action Item 추출하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI 응답은 문자열 형태의 JSON으로 반환되기 때문에, 백엔드에서는 &lt;b&gt;ObjectMapper&lt;/b&gt;를 사용해 JSON을 파싱한다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;그중 &lt;b&gt;actionItems&lt;/b&gt; 배열을 순회하면서 각각의 할 일을 `ActionItem` 엔티티로 변환해 DB에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685470642&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(aiJsonResponse);

JsonNode actionItemsNode = root.path(&quot;actionItems&quot;);

if (actionItemsNode.isArray()) {
  for (JsonNode node : actionItemsNode) {
    ActionItem item = new ActionItem();

    item.setTitle(node.path(&quot;title&quot;).asText(&quot;새로운 할 일&quot;));
    item.setMemo(node.path(&quot;memo&quot;).asText(&quot;내용 없음&quot;));

    item.setMeeting(meeting);
    item.setCompleted(false);
    item.setActivated(true);
    item.setIsConfirmed(true);

    item.setPhase(node.path(&quot;phase&quot;).asLong(1L));
    item.setScope(&quot;TEAM&quot;);
    item.setImage(&quot;default.png&quot;);

    actionItemRepository.save(item);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가&amp;nbsp;생성한&amp;nbsp;결과를&amp;nbsp;그대로&amp;nbsp;화면에&amp;nbsp;보여주는&amp;nbsp;것이&amp;nbsp;아니라,&amp;nbsp;서비스에서&amp;nbsp;관리&amp;nbsp;가능한&amp;nbsp;ActionItem&amp;nbsp;엔티티로&amp;nbsp;저장한다는&amp;nbsp;점이&amp;nbsp;중요하다. &lt;br /&gt;&lt;br /&gt;이를&amp;nbsp;통해&amp;nbsp;사용자는&amp;nbsp;이후&amp;nbsp;화면에서&amp;nbsp;할&amp;nbsp;일&amp;nbsp;제목,&amp;nbsp;마감일,&amp;nbsp;담당자를&amp;nbsp;수정하거나&amp;nbsp;삭제할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;즉,&amp;nbsp;AI는&amp;nbsp;초안을&amp;nbsp;생성하고,&amp;nbsp;사용자는&amp;nbsp;최종적으로&amp;nbsp;이를&amp;nbsp;확인하고&amp;nbsp;수정하는&amp;nbsp;구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 생성된 Action Item 조회 및 수정 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된&amp;nbsp;Action&amp;nbsp;Item은&amp;nbsp;회의&amp;nbsp;상세&amp;nbsp;화면이나&amp;nbsp;할&amp;nbsp;일&amp;nbsp;관리&amp;nbsp;화면에서&amp;nbsp;조회할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;KNOTE에서는&amp;nbsp;전체&amp;nbsp;Action&amp;nbsp;Item&amp;nbsp;조회,&amp;nbsp;특정&amp;nbsp;담당자별&amp;nbsp;조회,&amp;nbsp;특정&amp;nbsp;회의별&amp;nbsp;조회&amp;nbsp;API를&amp;nbsp;제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685857468&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;/meeting/{meetingId}&quot;)
public ResponseEntity&amp;lt;List&amp;lt;ActionItemDTO&amp;gt;&amp;gt; getByMeeting(@PathVariable Long meetingId) {
  return ResponseEntity.ok(actionItemService.getByMeetingId(meetingId));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685868720&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional(readOnly = true)
public List&amp;lt;ActionItemDTO&amp;gt; getByMeetingId(Long meetingId) {
  List&amp;lt;ActionItem&amp;gt; actionItems = actionItemRepository.findByMeetingId(meetingId);

  return actionItems.stream()
      .map(item -&amp;gt; mapToDTO(item, new ActionItemDTO()))
      .collect(Collectors.toList());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp;사용자가&amp;nbsp;AI가&amp;nbsp;만든&amp;nbsp;할&amp;nbsp;일을&amp;nbsp;그대로&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;아니라,&amp;nbsp;제목이나&amp;nbsp;마감&amp;nbsp;기한,&amp;nbsp;담당자를&amp;nbsp;직접&amp;nbsp;수정할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;PATCH&amp;nbsp;API도&amp;nbsp;구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779685915711&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PatchMapping(&quot;/{id}&quot;)
public ResponseEntity&amp;lt;Void&amp;gt; patchActionItem(
    @PathVariable Long id,
    @RequestBody ActionItemPatchRequest request
) {
  actionItemService.patchActionItem(id, request);
  return ResponseEntity.ok().build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 액션아이템의 마감일은 AI 응답에 포함될 수 있지만, 현재 구현에서는 기본값으로 회의 생성일 기준 3일 뒤를 설정하도록 처리했다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;이는&amp;nbsp;AI가&amp;nbsp;마감일을&amp;nbsp;정확히&amp;nbsp;추출하지&amp;nbsp;못하는&amp;nbsp;경우에도&amp;nbsp;Action&amp;nbsp;Item이&amp;nbsp;유효한&amp;nbsp;기본값을&amp;nbsp;갖도록&amp;nbsp;하기&amp;nbsp;위함이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; OpenAI로 회의 요약과 Action Item 생성하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deepgram을&amp;nbsp;통해&amp;nbsp;화자별&amp;nbsp;회의록이&amp;nbsp;생성되면,&amp;nbsp;다음&amp;nbsp;단계에서는&amp;nbsp;OpenAI&amp;nbsp;API를&amp;nbsp;사용해&amp;nbsp;회의&amp;nbsp;내용을&amp;nbsp;분석한다. &lt;br /&gt;&lt;br /&gt;이때&amp;nbsp;단순히&amp;nbsp;&amp;ldquo;회의를&amp;nbsp;요약해줘&amp;rdquo;라고&amp;nbsp;요청하지&amp;nbsp;않고,&amp;nbsp;KNOTE에서&amp;nbsp;바로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;JSON&amp;nbsp;구조로&amp;nbsp;응답하도록&amp;nbsp;프롬프트를&amp;nbsp;설계했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779686149229&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public String summarize(String transcript) {
  String url = baseUrl + &quot;/chat/completions&quot;;

  String systemPrompt =
      &quot;너는 전문 회의 기록가이자 프로젝트 매니저야. 제공된 회의 스크립트를 분석해서 'Action Items(할 일)'를 추출해.\n\n&quot; +
      &quot;1. 오직 회의 스크립트에서 언급된 할 일만 추출해.\n&quot; +
      &quot;2. 마감 기한이 있다면 dueDate에 작성해.\n&quot; +
      &quot;3. 해당 할 일을 언급한 화자를 suggestedSpeaker에 작성해.\n&quot; +
      &quot;4. 반드시 JSON 형식으로만 응답해.&quot;;

  Map&amp;lt;String, Object&amp;gt; body = new HashMap&amp;lt;&amp;gt;();
  body.put(&quot;model&quot;, &quot;gpt-4o-mini&quot;);
  body.put(&quot;messages&quot;, List.of(
      Map.of(&quot;role&quot;, &quot;system&quot;, &quot;content&quot;, systemPrompt),
      Map.of(&quot;role&quot;, &quot;user&quot;, &quot;content&quot;, transcript)
  ));

  body.put(&quot;response_format&quot;, Map.of(&quot;type&quot;, &quot;json_object&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI 응답 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1779686180050&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;title&quot;: &quot;포스터 제작 회의&quot;,
  &quot;summarySegments&quot;: [
    &quot;포스터의 색상과 레이아웃 수정 방향을 논의했다.&quot;,
    &quot;발표 자료와 최종본 공유 일정을 정했다.&quot;
  ],
  &quot;actionItems&quot;: [
    {
      &quot;title&quot;: &quot;포스터 색상과 레이아웃 수정&quot;,
      &quot;memo&quot;: &quot;KNOTE 로고 색감에 맞춰 포스터 디자인을 정리한다.&quot;,
      &quot;suggestedSpeaker&quot;: &quot;화자 1&quot;,
      &quot;dueDate&quot;: &quot;2026-05-26T18:00:00&quot;,
      &quot;phase&quot;: 2
    },
    {
      &quot;title&quot;: &quot;수정본 공유&quot;,
      &quot;memo&quot;: &quot;수정된 포스터 최종본을 팀원들에게 공유한다.&quot;,
      &quot;suggestedSpeaker&quot;: &quot;화자 0&quot;,
      &quot;dueDate&quot;: &quot;2026-05-27T18:00:00&quot;,
      &quot;phase&quot;: 5
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 실행 방법 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행을&amp;nbsp;위해서는&amp;nbsp;Deepgram&amp;nbsp;API&amp;nbsp;Key와&amp;nbsp;OpenAI&amp;nbsp;API&amp;nbsp;Key가&amp;nbsp;필요하다. &lt;br /&gt;&lt;br /&gt;`application.yml`에는&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;외부&amp;nbsp;API&amp;nbsp;설정을&amp;nbsp;추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779686311198&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;deepgram:
  api:
    key: ${DEEPGRAM_API_KEY}
    url: https://api.deepgram.com/v1/listen

openai:
  api:
    key: ${OPENAI_API_KEY}
    url: https://api.openai.com/v1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후&amp;nbsp;회의&amp;nbsp;녹음&amp;nbsp;파일을&amp;nbsp;업로드하는&amp;nbsp;API를&amp;nbsp;호출한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 기술에 대해 고민한 점을 얘기해보면서 마무리를 지어보고싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫&amp;nbsp;번째로&amp;nbsp;고려한&amp;nbsp;점은&amp;nbsp;화자&amp;nbsp;분리였다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;회의&amp;nbsp;서비스에서는&amp;nbsp;단순히&amp;nbsp;내용을&amp;nbsp;텍스트로&amp;nbsp;바꾸는&amp;nbsp;것보다,&amp;nbsp;누가&amp;nbsp;어떤&amp;nbsp;말을&amp;nbsp;했는지&amp;nbsp;보존하는&amp;nbsp;것이&amp;nbsp;중요하다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;이&amp;nbsp;때문에&amp;nbsp;Whisper&amp;nbsp;대신&amp;nbsp;Deepgram을&amp;nbsp;사용했고,&amp;nbsp;`diarize=true`&amp;nbsp;옵션을&amp;nbsp;적용했다. &lt;br /&gt;&lt;br /&gt;두&amp;nbsp;번째로&amp;nbsp;고려한&amp;nbsp;점은&amp;nbsp;응답&amp;nbsp;형식이다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;LLM&amp;nbsp;응답이&amp;nbsp;자유로운&amp;nbsp;문장&amp;nbsp;형태로&amp;nbsp;오면&amp;nbsp;백엔드에서&amp;nbsp;안정적으로&amp;nbsp;파싱하기&amp;nbsp;어렵다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;따라서&amp;nbsp;JSON&amp;nbsp;형식을&amp;nbsp;강제하고,&amp;nbsp;`title`,&amp;nbsp;`summarySegments`,&amp;nbsp;`actionItems`처럼&amp;nbsp;필요한&amp;nbsp;필드를&amp;nbsp;명확히&amp;nbsp;지정했다. &lt;br /&gt;&lt;br /&gt;세&amp;nbsp;번째로&amp;nbsp;고려한&amp;nbsp;점은&amp;nbsp;사용자&amp;nbsp;수정&amp;nbsp;가능성이다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;AI가&amp;nbsp;생성한&amp;nbsp;Action&amp;nbsp;Item이&amp;nbsp;항상&amp;nbsp;완벽하지는&amp;nbsp;않기&amp;nbsp;때문에,&amp;nbsp;사용자가&amp;nbsp;제목,&amp;nbsp;마감일,&amp;nbsp;담당자를&amp;nbsp;수정할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;PATCH&amp;nbsp;API를&amp;nbsp;함께&amp;nbsp;제공했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번&amp;nbsp;구현을&amp;nbsp;통해&amp;nbsp;KNOTE는&amp;nbsp;회의&amp;nbsp;녹음&amp;nbsp;파일을&amp;nbsp;단순히&amp;nbsp;텍스트로&amp;nbsp;변환하는&amp;nbsp;데서&amp;nbsp;끝나지&amp;nbsp;않고,&amp;nbsp;실제&amp;nbsp;사용자가&amp;nbsp;관리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;Action&amp;nbsp;Item으로&amp;nbsp;연결할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;되었다. &lt;br /&gt;&lt;br /&gt;Deepgram은&amp;nbsp;화자&amp;nbsp;분리를&amp;nbsp;통해&amp;nbsp;회의&amp;nbsp;맥락을&amp;nbsp;보존하고,&amp;nbsp;OpenAI는&amp;nbsp;해당&amp;nbsp;회의록에서&amp;nbsp;요약과&amp;nbsp;할&amp;nbsp;일을&amp;nbsp;추출한다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;그리고&amp;nbsp;백엔드는&amp;nbsp;AI&amp;nbsp;결과를&amp;nbsp;ActionItem&amp;nbsp;엔티티로&amp;nbsp;저장해&amp;nbsp;회의&amp;nbsp;상세&amp;nbsp;화면과&amp;nbsp;할&amp;nbsp;일&amp;nbsp;관리&amp;nbsp;화면에서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;연결한다. &lt;br /&gt;&lt;br /&gt;즉,&amp;nbsp;KNOTE의&amp;nbsp;핵심&amp;nbsp;기능은&amp;nbsp;다음&amp;nbsp;흐름으로&amp;nbsp;정리할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;&amp;ldquo;회의&amp;nbsp;녹음&amp;nbsp;&amp;rarr;&amp;nbsp;화자별&amp;nbsp;회의록&amp;nbsp;&amp;rarr;&amp;nbsp;AI&amp;nbsp;요약&amp;nbsp;&amp;rarr;&amp;nbsp;Action&amp;nbsp;Item&amp;nbsp;생성&amp;nbsp;&amp;rarr;&amp;nbsp;사용자&amp;nbsp;확인&amp;nbsp;및&amp;nbsp;수정&amp;rdquo; &lt;br /&gt;&lt;br /&gt;이&amp;nbsp;구조를&amp;nbsp;통해&amp;nbsp;회의가&amp;nbsp;끝난&amp;nbsp;뒤&amp;nbsp;사용자가&amp;nbsp;직접&amp;nbsp;회의록을&amp;nbsp;다시&amp;nbsp;읽고&amp;nbsp;할&amp;nbsp;일을&amp;nbsp;정리해야&amp;nbsp;하는&amp;nbsp;부담을&amp;nbsp;줄일&amp;nbsp;수&amp;nbsp;있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고용으로 우리 AllIsWell 팀의 깃허브 주소 또한 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(아직 개발이 진행 중이라는 점은 비밀)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/ALLISWELL-Lab&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ALLISWELL-Lab&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>졸업 프로젝트 - 그로쓰</category>
      <category>AI</category>
      <category>STT</category>
      <category>개발</category>
      <category>졸업프로젝트</category>
      <author>yoozafree</author>
      <guid isPermaLink="true">https://yoozafree.tistory.com/2</guid>
      <comments>https://yoozafree.tistory.com/2#entry2comment</comments>
      <pubDate>Mon, 25 May 2026 14:35:57 +0900</pubDate>
    </item>
    <item>
      <title>STT 사용 파이프라인과 현존하는 STT 서비스들 비교</title>
      <link>https://yoozafree.tistory.com/1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성일: 2025.11.27&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 포스팅으로 졸업 프로젝트에 관한 글을 올리게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;먼저 우리 팀의 주제는&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; 대학생 개발자 팀의 효율적인 협업을 위한 회의록 기반의 지능형 진척 관리 및 피드백 시스템 &lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 프로젝트 협업 환경에서 가장 반복되는 작업 중 하나는 &lt;b&gt;회의록 작성&lt;/b&gt;이다.&lt;br /&gt;하지만 회의 내용을 모두 사람이 기록하고 정리하는 것은 시간이 오래 걸리고, 중요한 논의가 누락되거나 주관적 해석이 개입된다는 문제가 있다. 특히, 개발 프로젝트에 있어 대학생들은 익숙지 않고, 어려움을 겪기에 그에 대한 고민을 해결해줄 수 있는 방안이 뭐가 있을까 고민하다가 나온 주제다. 이를 위해 우리 사이트에서 회의록을 녹음 후 이를 자동 텍스트화 및 요약을 진행하고, 이를 액션 아이템, 즉 &lt;b&gt;To-Do 화&lt;/b&gt;를 시키는 것이 프로젝트 주요 기능을 위한 제일 우선이 되어야 하는 흐름에 대한 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 우리가 졸업 프로젝트에서 직접 구현 중인 회의록 자동 생성 및 요약과 관련된 기술 파이프라인과 해당 기술을 위해 활용될 여러 STT 서비스들에 대해 말해보고자 한다.&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;240&quot; data-start=&quot;210&quot; data-ke-size=&quot;size23&quot;&gt;회의록 자동 생성 및 요약 기술 파이프라인&lt;/h3&gt;
&lt;h4 data-end=&quot;549&quot; data-start=&quot;520&quot; data-ke-size=&quot;size20&quot;&gt;1. 서비스 내 녹음 기능(Recording)&lt;/h4&gt;
&lt;p data-end=&quot;647&quot; data-start=&quot;551&quot; data-ke-size=&quot;size16&quot;&gt;우리 서비스는 사용자가 별도 녹음 파일을 업로드할 필요가 없다.&lt;br /&gt;회의 화면에서 &lt;b&gt;바로 녹음 버튼을 누르면 음성이 수집&lt;/b&gt;되며, 회의가 끝나면 자동으로 서버에 저장된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;768&quot; data-start=&quot;649&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;696&quot; data-start=&quot;649&quot;&gt;React.js 기반 프론트엔드에서 MediaRecorder를 활용해 녹음&lt;/li&gt;
&lt;li data-end=&quot;734&quot; data-start=&quot;697&quot;&gt;녹음된 Blob 데이터를 Spring Boot 백엔드로 전송&lt;/li&gt;
&lt;li data-end=&quot;768&quot; data-start=&quot;735&quot;&gt;백엔드는 파일을 임시 저장한 후 STT 처리 단계로 넘김&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;867&quot; data-start=&quot;770&quot; data-ke-size=&quot;size16&quot;&gt;이 구조는 우리가 정의했던 문제 중 &lt;b&gt;&amp;ldquo;회의 기록이 여러 툴로 흩어지는 문제&amp;rdquo;&lt;/b&gt;를 해결하는 첫 단계다.&lt;br /&gt;&lt;b&gt;녹음&amp;ndash;전환&amp;ndash;정리&lt;/b&gt;까지 모든 과정이 하나의 서비스에서 처리된다.&lt;/p&gt;
&lt;hr data-end=&quot;872&quot; data-start=&quot;869&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;908&quot; data-start=&quot;874&quot; data-ke-size=&quot;size20&quot;&gt;2. STT(Speech-to-Text) 변환 단계&lt;/h4&gt;
&lt;p data-end=&quot;934&quot; data-start=&quot;909&quot; data-ke-size=&quot;size16&quot;&gt;(현재 STT 엔진은 비교 후 선정 예정)&lt;/p&gt;
&lt;p data-end=&quot;1088&quot; data-start=&quot;936&quot; data-ke-size=&quot;size16&quot;&gt;녹음된 음성은 &lt;b&gt;STT 엔진을 통해 텍스트로 변환&lt;/b&gt;된다.&lt;br /&gt;우리는 현재 NHN, CLOVA 같은 국내 엔진부터 Google Cloud, Daglo까지&lt;br /&gt;성능&amp;middot;가격&amp;middot;한국어 최적화 등 여러 기준으로 테스트 중이며,&lt;br /&gt;최종적으로 하나의 엔진을 서비스에 탑재할 예정이다.&lt;/p&gt;
&lt;p data-end=&quot;1122&quot; data-start=&quot;1090&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 백엔드에서는 다음 흐름으로 진행된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1199&quot; data-start=&quot;1124&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1142&quot; data-start=&quot;1124&quot;&gt;전송된 음성을 일시 저장&lt;/li&gt;
&lt;li data-end=&quot;1159&quot; data-start=&quot;1143&quot;&gt;STT API에 요청&lt;/li&gt;
&lt;li data-end=&quot;1177&quot; data-start=&quot;1160&quot;&gt;회의 원문 텍스트 수신&lt;/li&gt;
&lt;li data-end=&quot;1199&quot; data-start=&quot;1178&quot;&gt;텍스트를 DB(MySQL)에 저장&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1286&quot; data-start=&quot;1201&quot; data-ke-size=&quot;size16&quot;&gt;STT 품질은 이후 단계(요약&amp;middot;To-do 생성&amp;middot;진척 분석)에 크게 영향을 주기 때문에&lt;br /&gt;정확한 한국어 인식이 가능한 엔진을 선정하는 것을 목표로 한다.&lt;/p&gt;
&lt;hr data-end=&quot;1291&quot; data-start=&quot;1288&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1327&quot; data-start=&quot;1293&quot; data-ke-size=&quot;size20&quot;&gt;3. 텍스트 전처리(Text Preprocessing)&lt;/h4&gt;
&lt;p data-end=&quot;1389&quot; data-start=&quot;1329&quot; data-ke-size=&quot;size16&quot;&gt;STT 결과는 바로 LLM에 넣기 어렵기 때문에&lt;br /&gt;Spring Boot에서 텍스트 전처리 로직을 수행한다.&lt;/p&gt;
&lt;p data-end=&quot;1409&quot; data-start=&quot;1391&quot; data-ke-size=&quot;size16&quot;&gt;전처리 주요 기능은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1526&quot; data-start=&quot;1411&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1431&quot; data-start=&quot;1411&quot;&gt;구두점 복원 및 띄어쓰기 보정&lt;/li&gt;
&lt;li data-end=&quot;1460&quot; data-start=&quot;1432&quot;&gt;불필요한 발화 제거(&amp;ldquo;음&amp;hellip;&amp;rdquo;, &amp;ldquo;아&amp;hellip;&amp;rdquo; 등)&lt;/li&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1461&quot;&gt;문장 단위 재구성&lt;/li&gt;
&lt;li data-end=&quot;1509&quot; data-start=&quot;1475&quot;&gt;LLM 입력 길이(Limit)를 고려한 Chunk 분할&lt;/li&gt;
&lt;li data-end=&quot;1526&quot; data-start=&quot;1510&quot;&gt;필요 시 화자 정보 구조화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1577&quot; data-start=&quot;1528&quot; data-ke-size=&quot;size16&quot;&gt;이 단계는 전처리가 잘 될수록 요약 및 To-do 생성의 품질이 비약적으로 향상된다.&lt;/p&gt;
&lt;hr data-end=&quot;1582&quot; data-start=&quot;1579&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1611&quot; data-start=&quot;1584&quot; data-ke-size=&quot;size20&quot;&gt;4. 회의 요약(Summarization)&lt;/h4&gt;
&lt;p data-end=&quot;1651&quot; data-start=&quot;1613&quot; data-ke-size=&quot;size16&quot;&gt;전처리된 텍스트는 &lt;b&gt;OpenAI API&lt;/b&gt;를 이용해 자동 요약된다.&lt;/p&gt;
&lt;p data-end=&quot;1682&quot; data-start=&quot;1653&quot; data-ke-size=&quot;size16&quot;&gt;우리 시스템은 다음 세 가지 형태의 요약을 생성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1760&quot; data-start=&quot;1684&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1700&quot; data-start=&quot;1684&quot;&gt;&lt;b&gt;전체 회의 요약&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1729&quot; data-start=&quot;1701&quot;&gt;&lt;b&gt;핵심 논의 정리(Key Points)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1760&quot; data-start=&quot;1730&quot;&gt;&lt;b&gt;결정된 사항(Decisions Made)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1891&quot; data-start=&quot;1762&quot; data-ke-size=&quot;size16&quot;&gt;이 구조는 페르소나가 원했던&lt;br /&gt;&lt;b&gt;&amp;ldquo;회의 내용을 한눈에 파악할 수 있는 기능&amp;rdquo;&lt;/b&gt;을 충족한다.&lt;br /&gt;팀원들은 더 이상 긴 회의록 처음부터 끝까지 읽을 필요 없이, 혹은 회의들을 기억해내지 않아도&lt;br /&gt;요약된 정보만 보고도 팀 상황을 쉽게 파악할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1975&quot; data-start=&quot;1893&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 설계에는 역할 기반 프롬프트 + 조건 기반 구조화 요청이 사용되며,&lt;br /&gt;이는 요약 품질의 안정성과 일관성을 유지하는 데 효과적이다.&lt;/p&gt;
&lt;hr data-end=&quot;1980&quot; data-start=&quot;1977&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2013&quot; data-start=&quot;1982&quot; data-ke-size=&quot;size20&quot;&gt;5. Action Item(To-do) 자동 생성&lt;/h4&gt;
&lt;p data-end=&quot;2069&quot; data-start=&quot;2015&quot; data-ke-size=&quot;size16&quot;&gt;요약 결과를 바탕으로&lt;br /&gt;&lt;b&gt;회의에서 나온 할 일(Action Item)&lt;/b&gt;을 자동으로 추출한다.&lt;/p&gt;
&lt;p data-end=&quot;2099&quot; data-start=&quot;2071&quot; data-ke-size=&quot;size16&quot;&gt;OpenAI API를 사용해 다음 항목을 발굴한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2188&quot; data-start=&quot;2101&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2124&quot; data-start=&quot;2101&quot;&gt;해야 할 업무(Task title)&lt;/li&gt;
&lt;li data-end=&quot;2139&quot; data-start=&quot;2125&quot;&gt;담당자(owner)&lt;/li&gt;
&lt;li data-end=&quot;2158&quot; data-start=&quot;2140&quot;&gt;데드라인(due_date)&lt;/li&gt;
&lt;li data-end=&quot;2177&quot; data-start=&quot;2159&quot;&gt;우선순위(priority)&lt;/li&gt;
&lt;li data-end=&quot;2188&quot; data-start=&quot;2178&quot;&gt;관련 논의 출처&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2260&quot; data-start=&quot;2190&quot; data-ke-size=&quot;size16&quot;&gt;이 정보는 JSON 형태로 구조화되어 저장되며, React.js UI에서 직관적인 To-do 리스트 형태로 확인할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2260&quot; data-start=&quot;2190&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2344&quot; data-start=&quot;2262&quot; data-ke-size=&quot;size16&quot;&gt;이 기능은 우리가 정의했던 Pain Point 중 &lt;br /&gt;&lt;b&gt;&amp;ldquo;회의 피드백이 문서에만 머물고 실행으로 이어지지 않는다&amp;rdquo; &lt;/b&gt;는 문제를 해결하기 위한 핵심 기능이다.&lt;/p&gt;
&lt;p data-end=&quot;2405&quot; data-start=&quot;2346&quot; data-ke-size=&quot;size16&quot;&gt;또한 팀장 혹은 일부 팀원이 직접 정리하고 분배하던 업무를 시스템이 자동으로 제안해줘 관리 부담을 줄여준다.&lt;/p&gt;
&lt;hr data-end=&quot;2410&quot; data-start=&quot;2407&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2433&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size20&quot;&gt;6. 피드백 &amp;amp; 진척 관리 연계&lt;/h4&gt;
&lt;p data-end=&quot;2506&quot; data-start=&quot;2435&quot; data-ke-size=&quot;size16&quot;&gt;To-do가 생성되면 Spring Boot 백엔드에서는 다음의 추가 로직을 수행하여 진척도를 계산하고 피드백을 생성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2624&quot; data-start=&quot;2508&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2535&quot; data-start=&quot;2508&quot;&gt;To-do 완료 여부 체크 (진척도 반영)&lt;/li&gt;
&lt;li data-end=&quot;2554&quot; data-start=&quot;2536&quot;&gt;완료 속도 / 난이도 분석&lt;/li&gt;
&lt;li data-end=&quot;2590&quot; data-start=&quot;2555&quot;&gt;일정 동기화 (Google Calendar API 이용)&lt;/li&gt;
&lt;li data-end=&quot;2624&quot; data-start=&quot;2591&quot;&gt;성실도 기반 간단 피드백 생성(OpenAI API 연계)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2673&quot; data-start=&quot;2626&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;직관적인 진행 상황 확인&amp;rdquo;&lt;/b&gt;을 가능하게 한다.&lt;/p&gt;
&lt;p data-end=&quot;2736&quot; data-start=&quot;2675&quot; data-ke-size=&quot;size16&quot;&gt;또한 일정은 Google Calendar API와 동기화되면서 팀/개인 일정 관리의 단절 문제도 해결된다.&lt;/p&gt;
&lt;hr data-end=&quot;2741&quot; data-start=&quot;2738&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2759&quot; data-start=&quot;2743&quot; data-ke-size=&quot;size20&quot;&gt;전체 파이프라인 요약&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;3031&quot; data-start=&quot;2761&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2797&quot; data-start=&quot;2761&quot;&gt;&lt;b&gt;서비스 내 녹음 &amp;rarr; React.js + 번들 저장&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2848&quot; data-start=&quot;2798&quot;&gt;&lt;b&gt;STT 변환 &amp;rarr; Spring Boot에서 API 요청 (엔진 미선정 상태)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2886&quot; data-start=&quot;2849&quot;&gt;&lt;b&gt;텍스트 전처리 &amp;rarr; 구두점&amp;middot;띄어쓰기&amp;middot;불필요 발화 제거&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2934&quot; data-start=&quot;2887&quot;&gt;&lt;b&gt;회의 요약 &amp;rarr; OpenAI API 기반 자동 Summarization&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2977&quot; data-start=&quot;2935&quot;&gt;&lt;b&gt;Action Item 생성 &amp;rarr; 구조화된 To-do 자동 추출&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;3031&quot; data-start=&quot;2978&quot;&gt;&lt;b&gt;진척 분석 &amp;amp; 일정 연계 &amp;rarr; Google Calendar API + 진행률 분석&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;3129&quot; data-start=&quot;3033&quot; data-ke-size=&quot;size16&quot;&gt;이 모든 데이터는 MySQL에 저장되며, React UI에서 가볍고 직관적인 형태로 확인할 수 있다.&lt;br /&gt;Docker 및 vercel을 활용해 전체 서비스는 컨테이너 기반으로 배포될 예정이다.&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;다음으로는 현존하는 STT 서비스들의 특징 비교를 통해 우리팀이 최종적으로 사용할 수 있을 후보들을 리스트업 해보겠다.&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;598&quot; data-start=&quot;461&quot; data-ke-size=&quot;size23&quot;&gt;STT 비교 분석&lt;/h3&gt;
&lt;h4 data-end=&quot;475&quot; data-start=&quot;443&quot; data-ke-size=&quot;size20&quot;&gt;1) NHN Cloud Speech-to-Text&lt;/h4&gt;
&lt;p data-end=&quot;667&quot; data-start=&quot;476&quot; data-ke-size=&quot;size16&quot;&gt;NHN Cloud는 &lt;b&gt;한국어 최적화된 STT 엔진&lt;/b&gt;을 제공하는 대표적인 국내 클라우드 서비스다. 음성 파일 업로드 방식과 실시간 스트리밍 방식 모두 지원하며, 짧은 음성(싱크 방식)과 긴 음성(비동기 방식)을 구분해서 처리한다.&lt;br /&gt;가격은 &lt;b&gt;600초(10분)까지 무료&lt;/b&gt;, 이후에는 &lt;b&gt;15초당 약 4원&lt;/b&gt;으로 비교적 저렴한 편이다.&lt;/p&gt;
&lt;p data-end=&quot;820&quot; data-start=&quot;669&quot; data-ke-size=&quot;size16&quot;&gt;성능은 자연스러운 대화&amp;middot;발화 위주의 음성에서 안정된 수준이며, 발음이 조금 빠르거나 잡음이 섞인 환경에서는 오류율이 다소 증가할 수 있다. 그래도 &lt;b&gt;&amp;ldquo;한국어 특화 + 매우 저렴한 요금제&amp;rdquo;&lt;/b&gt;라는 장점 덕분에, 국내 사용자 중심의 서비스라면 도입 비용 부담이 거의 없다.&lt;/p&gt;
&lt;p data-end=&quot;820&quot; data-start=&quot;669&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kVds6/dJMcacVQV4u/662QL98ntCs4hzfQCakZH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kVds6/dJMcacVQV4u/662QL98ntCs4hzfQCakZH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kVds6/dJMcacVQV4u/662QL98ntCs4hzfQCakZH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkVds6%2FdJMcacVQV4u%2F662QL98ntCs4hzfQCakZH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1052&quot; height=&quot;548&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;825&quot; data-start=&quot;822&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;853&quot; data-start=&quot;827&quot; data-ke-size=&quot;size20&quot;&gt;2) Naver CLOVA Speech&lt;/h4&gt;
&lt;p data-end=&quot;993&quot; data-start=&quot;854&quot; data-ke-size=&quot;size16&quot;&gt;Naver CLOVA Speech는 &lt;b&gt;국내에서 가장 널리 사용되는 상업용 한국어 STT&lt;/b&gt; 중 하나다. 네이버 검색 및 지도 사업에서 활용되는 음성 처리 기술을 기반으로 하고 있어, &lt;b&gt;한국어 정확도는 국내 서비스 중 최상위권&lt;/b&gt;으로 평가된다.&lt;/p&gt;
&lt;p data-end=&quot;1114&quot; data-start=&quot;995&quot; data-ke-size=&quot;size16&quot;&gt;가격은 모델 종류에 따라 달라지지만 보통 &lt;b&gt;15초 단위 과금&lt;/b&gt;으로 제공되며, NHN과 비슷하거나 조금 높은 수준이다. 화자 분리, 오디오/영상 자동 처리, 긴 음성 처리 기능이 모두 지원되어 범용성이 높다.&lt;/p&gt;
&lt;p data-end=&quot;1255&quot; data-start=&quot;1116&quot; data-ke-size=&quot;size16&quot;&gt;실제 벤치마크에서도 &lt;b&gt;한국어 CER(문자 오류율)이 매우 낮은 편&lt;/b&gt;으로, 회의록 생성, 유튜브 자막, 서비스형 음성봇 등에서 많이 활용된다. 다만 가격이 아주 저렴한 편은 아니라서 대규모 음성을 장기간 처리해야 한다면 비용 부담이 생길 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1255&quot; data-start=&quot;1116&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1255&quot; data-start=&quot;1116&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1255&quot; data-start=&quot;1116&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMW8B3/dJMcacByFKf/4NKcUEVkKDjvZF2upi5Uy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMW8B3/dJMcacByFKf/4NKcUEVkKDjvZF2upi5Uy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMW8B3/dJMcacByFKf/4NKcUEVkKDjvZF2upi5Uy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMW8B3%2FdJMcacByFKf%2F4NKcUEVkKDjvZF2upi5Uy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;528&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;1260&quot; data-start=&quot;1257&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1297&quot; data-start=&quot;1262&quot; data-ke-size=&quot;size20&quot;&gt;3) Google Cloud Speech-to-Text&lt;/h4&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1298&quot; data-ke-size=&quot;size16&quot;&gt;Google Cloud Speech-to-Text는 전 세계적으로 가장 많이 사용되는 STT 서비스 중 하나로, &lt;b&gt;가장 다양한 언어와 포맷을 지원&lt;/b&gt;한다. 자동 구두점, 단어 레벨 타임스탬프, 화자 분리, 실시간 스트리밍 지원 등 기능적 완성도가 매우 높다.&lt;/p&gt;
&lt;p data-end=&quot;1596&quot; data-start=&quot;1447&quot; data-ke-size=&quot;size16&quot;&gt;가격은 &lt;b&gt;분당 약 $0.016(표준 모델 기준)&lt;/b&gt;으로 중간 수준이지만, 대규모로 사용하면 할인되는 구조다.&lt;br /&gt;한국어 인식률은 우수하지만, &lt;b&gt;한국어에 완전히 특화된 모델은 아니기 때문에&lt;/b&gt; NHN, CLOVA처럼 한국어 환경에서 최상위 성능을 보이진 않는다.&lt;/p&gt;
&lt;p data-end=&quot;1690&quot; data-start=&quot;1598&quot; data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고, &amp;ldquo;한국어 + 영어 + 일본어 + 중국어 등 다양한 언어가 혼재된 환경&amp;rdquo;, &amp;ldquo;글로벌 인프라 기반 서비스&amp;rdquo;를 구축해야 한다면 가장 안정적인 선택지다.&lt;/p&gt;
&lt;p data-end=&quot;1690&quot; data-start=&quot;1598&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1690&quot; data-start=&quot;1598&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OqTMu/dJMcacIkbpx/FZQzlgKswTpcjoWBOTKqS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OqTMu/dJMcacIkbpx/FZQzlgKswTpcjoWBOTKqS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OqTMu/dJMcacIkbpx/FZQzlgKswTpcjoWBOTKqS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOqTMu%2FdJMcacIkbpx%2FFZQzlgKswTpcjoWBOTKqS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;341&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;1695&quot; data-start=&quot;1692&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1722&quot; data-start=&quot;1697&quot; data-ke-size=&quot;size20&quot;&gt;4) Amazon Transcribe&lt;/h4&gt;
&lt;p data-end=&quot;1872&quot; data-start=&quot;1723&quot; data-ke-size=&quot;size16&quot;&gt;Amazon Transcribe는 AWS 생태계와 자연스럽게 연동되는 STT 서비스로, 긴 음성 처리 및 기업용 기능(Compliance 기능, Medical 모델 등)이 잘 갖추어져 있다. 가격은 사용량 기반 과금으로, Google Cloud와 유사한 레벨이다.&lt;/p&gt;
&lt;p data-end=&quot;2011&quot; data-start=&quot;1874&quot; data-ke-size=&quot;size16&quot;&gt;한국어 성능은 글로벌 서비스 중에서는 준수한 편이며, 특히 &lt;b&gt;긴 회의 음성&lt;/b&gt;에서 안정적인 결과를 낸다는 평가를 받는다. 다만 한국어 특화 모델이 있는 것은 아니기 때문에, 전문용어가 많거나 발음이 빠른 음성에서는 정확도가 낮아질 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2055&quot; data-start=&quot;2013&quot; data-ke-size=&quot;size16&quot;&gt;AWS 기반 인프라를 이미 사용하고 있다면 통합 관리 측면에서 장점이 크다.&lt;/p&gt;
&lt;p data-end=&quot;2055&quot; data-start=&quot;2013&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHuKYb/dJMcah3VEvB/anRokBCAK4KVM3KvtjEuG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHuKYb/dJMcah3VEvB/anRokBCAK4KVM3KvtjEuG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHuKYb/dJMcah3VEvB/anRokBCAK4KVM3KvtjEuG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHuKYb%2FdJMcah3VEvB%2FanRokBCAK4KVM3KvtjEuG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;159&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;2060&quot; data-start=&quot;2057&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2079&quot; data-start=&quot;2062&quot; data-ke-size=&quot;size20&quot;&gt;5) Daglo STT&lt;/h4&gt;
&lt;p data-end=&quot;2197&quot; data-start=&quot;2080&quot; data-ke-size=&quot;size16&quot;&gt;Daglo(다글로)는 최근 한국 개발자들 사이에서 주목받는 &lt;b&gt;한국어 특화 STT&lt;/b&gt; 서비스다. 글로벌 STT 대비 한국어 발음 처리, 억양, 자모 변환 등에 최적화되어 있으며, 실사용 후기가 좋은 편이다.&lt;/p&gt;
&lt;p data-end=&quot;2305&quot; data-start=&quot;2199&quot; data-ke-size=&quot;size16&quot;&gt;가격은 &lt;b&gt;초기 1시간 무료&lt;/b&gt;, 이후 시간당 과금 구조로 제공된다. 구체적인 비용이 NHN/CLOVA보다 높은 경우도 있지만, 한국어 정확도가 중요한 프로젝트에서는 좋은 선택지가 된다.&lt;/p&gt;
&lt;p data-end=&quot;2496&quot; data-start=&quot;2307&quot; data-ke-size=&quot;size16&quot;&gt;특히 Daglo는 &lt;b&gt;짧은 문장&amp;middot;대화체&amp;middot;일상 발화&lt;/b&gt;에서 안정적이며, 빠른 처리 속도와 한국어 모델의 최적화가 장점이다. 아직 Google/AWS만큼의 대규모 기능(화자 분리, 대형 파일 처리 등)은 부족한 면이 있지만, 한국어 정확도 + 간결한 요금 구조 때문에 회의록 자동화, 인터뷰 전사, 학습용 데이터셋 제작 등에서 많이 사용된다.&lt;/p&gt;
&lt;p data-end=&quot;2496&quot; data-start=&quot;2307&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc0JxG/dJMcafE2O8p/Lb459RmhPminTKNj607RK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc0JxG/dJMcafE2O8p/Lb459RmhPminTKNj607RK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc0JxG/dJMcafE2O8p/Lb459RmhPminTKNj607RK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc0JxG%2FdJMcafE2O8p%2FLb459RmhPminTKNj607RK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;300&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2496&quot; data-start=&quot;2307&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-end=&quot;2528&quot; data-start=&quot;2503&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2528&quot; data-start=&quot;2503&quot; data-ke-size=&quot;size18&quot;&gt;정리해보자면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2852&quot; data-start=&quot;2530&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2593&quot; data-start=&quot;2530&quot;&gt;&lt;b&gt;가격이 가장 중요한 국내 프로젝트&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;NHN Cloud&lt;/b&gt; (가장 저렴 + 한국어 무난)&lt;/li&gt;
&lt;li data-end=&quot;2657&quot; data-start=&quot;2595&quot;&gt;&lt;b&gt;한국어 인식률 최우선 + 안정적인 STT 엔진&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;Naver CLOVA Speech&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2732&quot; data-start=&quot;2659&quot;&gt;&lt;b&gt;글로벌 환경 + 여러 언어 + 대규모 서비스 구축&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;Google Cloud Speech-to-Text&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2796&quot; data-start=&quot;2734&quot;&gt;&lt;b&gt;AWS 기반 인프라 사용 / 긴 음성 처리 중요&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;Amazon Transcribe&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2852&quot; data-start=&quot;2798&quot;&gt;&lt;b&gt;한국어 발화 정확도 + 빠른 처리 속도 + 개발 편의성&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;Daglo&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들과 더 얘기를 해서 최종 확정을 지어야겠지만 총 정리를 해보자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국어 대화를 주로 하되, 영어로 된 용어로 소통이 잦은 &lt;i&gt;&lt;b&gt;&quot;개발&quot; &lt;/b&gt;&lt;/i&gt;도메인이라는 점을 상기시켜 해당 특징을 잘 고려해 정해봐야 할 것 같다.&amp;nbsp;&lt;/p&gt;</description>
      <category>졸업 프로젝트 - 스타트</category>
      <author>yoozafree</author>
      <guid isPermaLink="true">https://yoozafree.tistory.com/1</guid>
      <comments>https://yoozafree.tistory.com/1#entry1comment</comments>
      <pubDate>Thu, 27 Nov 2025 21:35:12 +0900</pubDate>
    </item>
  </channel>
</rss>