Skip to content

Commit 785135b

Browse files
committed
feat: stt 1차 짧은 대화 성공
1 parent 6758a12 commit 785135b

10 files changed

Lines changed: 250 additions & 11 deletions

File tree

‎build.gradle‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
plugins {
2-
id 'java'
3-
// id 'org.springframework.boot' version '4.0.1'
4-
id 'org.springframework.boot' version '3.2.5'
5-
// id 'io.spring.dependency-management' version '1.1.7'
6-
id 'io.spring.dependency-management' version '1.1.4'
7-
}
2+
id 'java'
3+
id 'org.springframework.boot' version '3.2.5'
4+
id 'io.spring.dependency-management' version '1.1.4'
5+
}
86

97
group = 'com.ureca'
108
version = '0.0.1-SNAPSHOT'
@@ -29,10 +27,9 @@ repositories {
2927
dependencies {
3028
implementation 'org.springframework.boot:spring-boot-starter-validation'
3129
implementation 'org.springframework.boot:spring-boot-starter-security'
32-
// implementation 'org.springframework.boot:spring-boot-starter-webmvc'
3330
implementation 'org.springframework.boot:spring-boot-starter-web'
34-
// implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:4.0.1'
3531
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
32+
implementation 'com.google.cloud:google-cloud-speech:4.46.0'
3633
compileOnly 'org.projectlombok:lombok'
3734
runtimeOnly 'com.mysql:mysql-connector-j'
3835
annotationProcessor 'org.projectlombok:lombok'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.ureca.unity.domain.stt.controller;
2+
3+
import com.ureca.unity.domain.stt.model.SttJob;
4+
import com.ureca.unity.domain.stt.service.SttService;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.web.bind.annotation.*;
7+
8+
@RestController
9+
@RequiredArgsConstructor
10+
@RequestMapping("/counselings")
11+
public class SttController {
12+
13+
private final SttService sttService;
14+
15+
@PostMapping("/{counselingId}/stt")
16+
public SttJob start(@PathVariable Long counselingId) {
17+
return sttService.startStt(counselingId);
18+
}
19+
20+
@GetMapping("/{counselingId}/stt")
21+
public SttJob get(@PathVariable Long counselingId) {
22+
return sttService.getStt(counselingId);
23+
}
24+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.ureca.unity.domain.stt.mapper;
2+
3+
import com.ureca.unity.domain.stt.model.SttJob;
4+
import org.apache.ibatis.annotations.Mapper;
5+
6+
@Mapper
7+
public interface SttMapper {
8+
9+
void insert(SttJob sttJob);
10+
11+
void updateResult(SttJob sttJob);
12+
13+
SttJob findByCounselingId(Long counselingId);
14+
15+
SttJob findById(Long sttJobId);
16+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.ureca.unity.domain.stt.model;
2+
3+
import lombok.*;
4+
5+
import java.time.LocalDateTime;
6+
7+
@Getter
8+
@Setter
9+
@NoArgsConstructor
10+
@AllArgsConstructor
11+
@Builder
12+
public class SttJob {
13+
14+
private Long sttJobId;
15+
private Long counselingId;
16+
private Long userId;
17+
18+
private String summaryType; // CALL / KEYWORD
19+
private String status; // LOADING(PROGRESS) / SUCCESS / FAIL
20+
21+
private String summaryText; // STT or LLM result
22+
private String keywords; // JSON 문자열로 처리 (임시)
23+
24+
private LocalDateTime createdAt;
25+
private LocalDateTime updatedAt;
26+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ureca.unity.domain.stt.response;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@AllArgsConstructor
8+
public class SttResponse {
9+
10+
private Long id;
11+
private String name;
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ureca.unity.domain.stt.service;
2+
3+
import com.ureca.unity.domain.stt.model.SttJob;
4+
5+
public interface SttService {
6+
7+
SttJob startStt(Long counselingId);
8+
9+
SttJob getStt(Long counselingId);
10+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.ureca.unity.domain.stt.service;
2+
3+
import com.google.cloud.speech.v1.*;
4+
import com.google.protobuf.ByteString;
5+
import com.ureca.unity.domain.stt.mapper.SttMapper;
6+
import com.ureca.unity.domain.stt.model.SttJob;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.stereotype.Service;
9+
10+
import java.nio.file.Files;
11+
import java.nio.file.Paths;
12+
import java.util.stream.Collectors;
13+
14+
@Service
15+
@RequiredArgsConstructor
16+
public class SttServiceImpl implements SttService {
17+
18+
private final SttMapper sttMapper;
19+
20+
@Override
21+
public SttJob startStt(Long counselingId) {
22+
23+
Long userId = 1L; // 임시
24+
25+
SttJob job = sttMapper.findByCounselingId(counselingId);
26+
27+
if (job == null) {
28+
job = SttJob.builder()
29+
.counselingId(counselingId)
30+
.userId(userId)
31+
.summaryType("CALL")
32+
.status("LOADING")
33+
.build();
34+
sttMapper.insert(job);
35+
}
36+
37+
try {
38+
39+
String audioPath = "C:/Users/bagju/Desktop/realsample.wav";
40+
41+
byte[] data = Files.readAllBytes(Paths.get(audioPath));
42+
ByteString audioBytes = ByteString.copyFrom(data);
43+
44+
RecognitionAudio audio = RecognitionAudio.newBuilder()
45+
.setContent(audioBytes)
46+
.build();
47+
48+
49+
RecognitionConfig config = RecognitionConfig.newBuilder()
50+
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
51+
.setLanguageCode("ko-KR")
52+
.setAudioChannelCount(2) // stereo
53+
.setEnableSeparateRecognitionPerChannel(true) // 채널 분리
54+
// sampleRateHertz는 WAV 헤더 기준 → 명시 안 함
55+
.build();
56+
57+
try (SpeechClient speechClient = SpeechClient.create()) {
58+
59+
RecognizeResponse response =
60+
speechClient.recognize(config, audio);
61+
62+
// 채널 상관없이 전부 합침 (지금은 검증 목적)
63+
String text = response.getResultsList().stream()
64+
.map(r -> r.getAlternatives(0).getTranscript())
65+
.collect(Collectors.joining(" "));
66+
67+
job.setStatus("SUCCESS");
68+
job.setSummaryText(text);
69+
}
70+
71+
} catch (Exception e) {
72+
e.printStackTrace();
73+
job.setStatus("FAIL");
74+
job.setSummaryText(null);
75+
}
76+
77+
sttMapper.updateResult(job);
78+
return job;
79+
}
80+
81+
@Override
82+
public SttJob getStt(Long counselingId) {
83+
return sttMapper.findByCounselingId(counselingId);
84+
}
85+
}

‎src/main/java/com/ureca/unity/global/config/SecurityConfig.java‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ public class SecurityConfig {
1717
private final JwtProvider jwtProvider;
1818
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
1919

20-
2120
@Bean
2221
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
2322

@@ -28,8 +27,15 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
2827
"/v3/api-docs/**",
2928
"/swagger-ui.html",
3029
"/api/auth/login/**",
31-
"/api/auth/refresh")
32-
.permitAll()
30+
"/api/auth/refresh",
31+
32+
// 🔴 여기 있던 잘못된 것 삭제
33+
// "/counselings/**/stt"
34+
35+
// ✅ 이 줄로 교체
36+
"/counselings/*/stt"
37+
).permitAll()
38+
3339
.requestMatchers("/api/auth/logout")
3440
.authenticated()
3541
.anyRequest().authenticated()
@@ -44,4 +50,5 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
4450

4551
return http.build();
4652
}
53+
4754
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE mapper
3+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5+
6+
<mapper namespace="com.ureca.unity.domain.stt.mapper.SttMapper">
7+
8+
<resultMap id="sttJobMap" type="com.ureca.unity.domain.stt.model.SttJob">
9+
<id property="sttJobId" column="stt_job_id"/>
10+
<result property="counselingId" column="counseling_id"/>
11+
<result property="userId" column="user_id"/>
12+
<result property="summaryType" column="summary_type"/>
13+
<result property="status" column="status"/>
14+
<result property="summaryText" column="summary_text"/>
15+
<result property="keywords" column="keywords"/>
16+
<result property="createdAt" column="created_at"/>
17+
<result property="updatedAt" column="updated_at"/>
18+
</resultMap>
19+
20+
<select id="findByCounselingId" resultMap="sttJobMap">
21+
SELECT *
22+
FROM stt_jobs
23+
WHERE counseling_id = #{counselingId}
24+
</select>
25+
26+
<select id="findById" resultMap="sttJobMap">
27+
SELECT *
28+
FROM stt_jobs
29+
WHERE stt_job_id = #{sttJobId}
30+
</select>
31+
32+
<insert id="insert"
33+
parameterType="com.ureca.unity.domain.stt.model.SttJob"
34+
useGeneratedKeys="true"
35+
keyProperty="sttJobId">
36+
INSERT INTO stt_jobs (
37+
counseling_id,
38+
user_id,
39+
summary_type,
40+
status
41+
)
42+
VALUES (
43+
#{counselingId},
44+
#{userId},
45+
#{summaryType},
46+
#{status}
47+
)
48+
</insert>
49+
50+
<update id="updateResult"
51+
parameterType="com.ureca.unity.domain.stt.model.SttJob">
52+
UPDATE stt_jobs
53+
SET
54+
status = #{status},
55+
summary_text = #{summaryText},
56+
updated_at = NOW()
57+
WHERE stt_job_id = #{sttJobId}
58+
</update>
59+
60+
</mapper>

‎tash list‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
stash@{0}: WIP on URECA-41/Feat/bookmark: d85b0f6 [URECA-29] Feat: JWT 기반 AccessToken/RefreshToken 발급/재발급 및 로그아웃 구현 (#17)
2+
stash@{1}: WIP on main: aa37cf2 fix: issue 양식 수정

0 commit comments

Comments
 (0)