stt service 빌드 에러 해결

This commit is contained in:
cyjadela
2025-10-24 10:04:58 +09:00
parent d2a92bcc20
commit 63615d823b
12 changed files with 2034 additions and 147 deletions
+90
View File
@@ -0,0 +1,90 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="stt" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<!-- 서버 설정 -->
<entry key="SERVER_PORT" value="8084" />
<entry key="SPRING_PROFILES_ACTIVE" value="dev" />
<!-- JWT 설정 -->
<entry key="JWT_SECRET" value="my-super-secret-jwt-key-for-hgzero-meeting-service-2024" />
<entry key="JWT_ACCESS_TOKEN_VALIDITY" value="3600" />
<entry key="JWT_REFRESH_TOKEN_VALIDITY" value="604800" />
<!-- 데이터베이스 설정 (STT 서비스 전용) -->
<entry key="DB_KIND" value="postgresql" />
<entry key="DB_HOST" value="4.230.65.89" />
<entry key="DB_PORT" value="5432" />
<entry key="DB_NAME" value="sttdb" />
<entry key="DB_USERNAME" value="hgzerouser" />
<entry key="DB_PASSWORD" value="Hi5Jessica!" />
<!-- Redis 설정 -->
<entry key="REDIS_HOST" value="20.249.177.114" />
<entry key="REDIS_PORT" value="6379" />
<entry key="REDIS_PASSWORD" value="Hi5Jessica!" />
<entry key="REDIS_DATABASE" value="2" />
<!-- JPA 설정 -->
<entry key="JPA_DDL_AUTO" value="update" />
<entry key="SHOW_SQL" value="true" />
<!-- CORS 설정 -->
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:3000,http://localhost:8080,http://localhost:8084" />
<!-- Azure Speech Services 설정 -->
<entry key="AZURE_SPEECH_SUBSCRIPTION_KEY" value="" />
<entry key="AZURE_SPEECH_REGION" value="koreacentral" />
<entry key="AZURE_SPEECH_LANGUAGE" value="ko-KR" />
<!-- Azure Blob Storage 설정 -->
<entry key="AZURE_BLOB_CONNECTION_STRING" value="" />
<entry key="AZURE_BLOB_CONTAINER_NAME" value="recordings" />
<!-- Azure Event Hub 설정 -->
<entry key="EVENTHUB_CONNECTION_STRING" value="Endpoint=sb://hgzero-eventhub-ns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=VUqZ9vFgu35E3c6RiUzoOGVUP8IZpFvlV+AEhC6sUpo=" />
<entry key="EVENTHUB_NAME" value="hgzero-eventhub-name" />
<entry key="AZURE_EVENTHUB_CONSUMER_GROUP" value="$Default" />
<!-- 로그 설정 -->
<entry key="LOG_LEVEL_APP" value="DEBUG" />
<entry key="LOG_LEVEL_WEB" value="INFO" />
<entry key="LOG_LEVEL_SQL" value="DEBUG" />
<entry key="LOG_LEVEL_SQL_TYPE" value="TRACE" />
<entry key="LOG_FILE_PATH" value="logs/stt.log" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="stt:bootRun" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<EXTENSION ID="com.intellij.execution.ExternalSystemRunConfigurationJavaExtension">
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
</ENTRIES>
</extension>
</EXTENSION>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
+1433
View File
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
package com.unicorn.hgzero.stt.config;
import com.unicorn.hgzero.common.exception.BusinessException;
import com.unicorn.hgzero.common.response.ApiResponse;
import com.unicorn.hgzero.common.dto.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import javax.validation.ConstraintViolationException;
import jakarta.validation.ConstraintViolationException;
/**
* STT 서비스 전역 예외 처리기
@@ -0,0 +1,85 @@
package com.unicorn.hgzero.stt.config;
import com.unicorn.hgzero.common.security.JwtTokenProvider;
import com.unicorn.hgzero.common.security.filter.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
/**
* Spring Security 설정
* JWT 기반 인증 및 API 보안 설정
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtTokenProvider jwtTokenProvider;
@Value("${cors.allowed-origins:http://localhost:3000,http://localhost:8080,http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084}")
private String allowedOrigins;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
// Actuator endpoints
.requestMatchers("/actuator/**").permitAll()
// Swagger UI endpoints - context path와 상관없이 접근 가능하도록 설정
.requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").permitAll()
// Health check
.requestMatchers("/health").permitAll()
// WebSocket endpoints
.requestMatchers("/ws/**").permitAll()
// All other requests require authentication
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// 환경변수에서 허용할 Origin 패턴 설정
String[] origins = allowedOrigins.split(",");
configuration.setAllowedOriginPatterns(Arrays.asList(origins));
// 허용할 HTTP 메소드
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
// 허용할 헤더
configuration.setAllowedHeaders(Arrays.asList(
"Authorization", "Content-Type", "X-Requested-With", "Accept",
"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"
));
// 자격 증명 허용
configuration.setAllowCredentials(true);
// Pre-flight 요청 캐시 시간
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
@@ -1,39 +1,63 @@
package com.unicorn.hgzero.stt.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* Swagger/OpenAPI 설정
* STT 서비스 API 문서화 설정
* STT Service API 문서화를 위한 설정
*/
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info()
.title("STT Service API")
.description("Speech-to-Text 서비스 API 문서")
.version("v1.0.0")
.contact(new Contact()
.name("STT Service Team")
.email("stt-service@unicorn.com"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html")))
.servers(List.of(
new Server().url("http://localhost:8083").description("로컬 개발 서버"),
new Server().url("https://dev-api.unicorn.com").description("개발 서버"),
new Server().url("https://api.unicorn.com").description("운영 서버")
));
.info(apiInfo())
.addServersItem(new Server()
.url("http://localhost:8084")
.description("Local Development"))
.addServersItem(new Server()
.url("{protocol}://{host}:{port}")
.description("Custom Server")
.variables(new io.swagger.v3.oas.models.servers.ServerVariables()
.addServerVariable("protocol", new io.swagger.v3.oas.models.servers.ServerVariable()
._default("http")
.description("Protocol (http or https)")
.addEnumItem("http")
.addEnumItem("https"))
.addServerVariable("host", new io.swagger.v3.oas.models.servers.ServerVariable()
._default("localhost")
.description("Server host"))
.addServerVariable("port", new io.swagger.v3.oas.models.servers.ServerVariable()
._default("8084")
.description("Server port"))))
.addSecurityItem(new SecurityRequirement().addList("Bearer Authentication"))
.components(new Components()
.addSecuritySchemes("Bearer Authentication", createAPIKeyScheme()));
}
private Info apiInfo() {
return new Info()
.title("STT Service API")
.description("음성-텍스트 변환 서비스 API")
.version("1.0.0")
.contact(new Contact()
.name("STT Service Development Team")
.email("dev@hgzero.com"));
}
private SecurityScheme createAPIKeyScheme() {
return new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.bearerFormat("JWT")
.scheme("bearer");
}
}
@@ -1,6 +1,6 @@
package com.unicorn.hgzero.stt.controller;
import com.unicorn.hgzero.common.response.ApiResponse;
import com.unicorn.hgzero.common.dto.ApiResponse;
import com.unicorn.hgzero.stt.dto.RecordingDto;
import com.unicorn.hgzero.stt.service.RecordingService;
import io.swagger.v3.oas.annotations.Operation;
@@ -15,7 +15,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import jakarta.validation.Valid;
/**
* 녹음 관리 컨트롤러
@@ -1,6 +1,6 @@
package com.unicorn.hgzero.stt.controller;
import com.unicorn.hgzero.common.response.ApiResponse;
import com.unicorn.hgzero.common.dto.ApiResponse;
import com.unicorn.hgzero.stt.dto.SpeakerDto;
import com.unicorn.hgzero.stt.service.SpeakerService;
import io.swagger.v3.oas.annotations.Operation;
@@ -15,7 +15,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import jakarta.validation.Valid;
/**
* 화자 관리 컨트롤러
@@ -1,6 +1,6 @@
package com.unicorn.hgzero.stt.controller;
import com.unicorn.hgzero.common.response.ApiResponse;
import com.unicorn.hgzero.common.dto.ApiResponse;
import com.unicorn.hgzero.stt.dto.TranscriptionDto;
import com.unicorn.hgzero.stt.dto.TranscriptSegmentDto;
import com.unicorn.hgzero.stt.service.TranscriptionService;
@@ -18,7 +18,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import jakarta.validation.Valid;
/**
* 음성 변환 컨트롤러
@@ -78,10 +78,12 @@ public class TranscriptionServiceImpl implements TranscriptionService {
updateRecordingStatistics(request.getRecordingId());
// 세그먼트 생성 이벤트 발행
LocalDateTime timestampAsLocalDateTime = java.time.Instant.ofEpochMilli(request.getTimestamp())
.atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
TranscriptionEvent.SegmentCreated event = TranscriptionEvent.SegmentCreated.of(
segmentId, request.getRecordingId(), recording.getMeetingId(),
recognizedText, speakerId, "화자-" + speakerId.substring(4),
request.getTimestamp(), 3.5, confidence, warningFlag
timestampAsLocalDateTime, 3.5, confidence, warningFlag
);
eventPublisher.publishAsync("transcription-events", event);
+1 -9
View File
@@ -99,20 +99,12 @@ springdoc:
# Logging Configuration
logging:
level:
root: ${LOG_LEVEL_ROOT:INFO}
com.unicorn.hgzero.stt: ${LOG_LEVEL_APP:DEBUG}
org.springframework.web: ${LOG_LEVEL_WEB:INFO}
org.springframework.security: ${LOG_LEVEL_SECURITY:DEBUG}
org.springframework.websocket: ${LOG_LEVEL_WEBSOCKET:DEBUG}
org.hibernate.SQL: ${LOG_LEVEL_SQL:DEBUG}
org.hibernate.type: ${LOG_LEVEL_SQL_TYPE:TRACE}
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: ${LOG_FILE:logs/stt-service.log}
logback:
rollingpolicy:
max-file-size: 10MB
max-history: 7
total-size-cap: 100MB
name: ${LOG_FILE_PATH:logs/stt.log}