Skip to content

Latest commit

ย 

History

287 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŽ™๏ธ Malbit (๋ง๋น›) Backend & AI Server

"๋ง๋น›(Malbit)"์€ ๊ตฌ์Œ์žฅ์• (Dysarthria) ๋ฐ ์–ธ์–ด ์žฅ์• ๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์—… ํ™˜๊ฒฝ์ด๋‚˜ ์ผ์ƒ์ƒํ™œ์—์„œ ๊ฒช๋Š” ์˜์‚ฌ์†Œํ†ต์  ์žฅ๋ฒฝ์„ ๊ทน๋ณตํ•˜๋„๋ก ๋•๋Š” AI ๊ธฐ๋ฐ˜ ์–ด์‹œ์Šคํ„ดํŠธ & ๋ฐœ์Œ ๊ฐœ์„  ํ›ˆ๋ จ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.

์ด ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋Š” ์‚ฌ์šฉ์ž์˜ ๊ตฌ์–ด ๋ถ„์„, ๋งž์ถคํ˜• ๋ฐœ์Œ ํ”ผ๋“œ๋ฐฑ(์ƒํ™ฉ๊ทน ์—ฐ์Šต), ๋‹จ๋ฌธ ๋ฆฌ๋งˆ์Šคํ„ฐ๋ง(๋ฐœํ™” ๋ณด์ •), ๊ทธ๋ฆฌ๊ณ  ํšŒ์˜๋ก/์—…๋ฌด ๋‚ด์šฉ์„ ์š”์•ฝํ•˜์—ฌ ์บ˜๋ฆฐ๋”์— ์—ฐ๋™ํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•˜๋Š” Spring Boot ๋ฐฑ์—”๋“œ ๋ฐ FastAPI AI ์„œ๋ฒ„๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ—๏ธ ์ „์ฒด ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ (Architecture Overview)

๋Œ€์šฉ๋Ÿ‰ ์Œ์„ฑ ์ฒ˜๋ฆฌ ๋ฐ ๋Œ€ํ˜• ์–ธ์–ด ๋ชจ๋ธ(LLM) ์ถ”๋ก ์„ ์•ˆ์ •์ ์ด๊ณ  ๋ฐ˜์‘ ์†๋„ ์ €ํ•˜ ์—†์ด ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด Java Spring Boot ๊ธฐ๋ฐ˜ ๋น„์ฆˆ๋‹ˆ์Šค/๋ณด์•ˆ ์„œ๋ฒ„์™€ Python FastAPI ๊ธฐ๋ฐ˜ AI ๋ชจ๋ธ ์ถ”๋ก  ์„œ๋ฒ„๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

graph TD
    Flutter[Flutter Mobile Client] <-->|REST API / JWT Auth| Boot[Spring Boot Backend <br> Java 21 / Spring Boot 3.2.4]
    Boot <-->|Async Non-blocking WebClient| Fast[FastAPI AI Server <br> Python / Uvicorn]
    
    subgraph AI Engine Pipeline
        Fast <-->|Local GPU / PyTorch Pipeline| Whisper[Custom Fine-tuned Whisper <br> whisper-dysarthria-ko / whisper-medium]
        Fast <-->|boto3 API Client| Bedrock[AWS Bedrock <br> Claude 3 Haiku]
    end
    
    Fast -->|Async HTTP Webhook / POST| BootCalendar[Spring Boot /api/calendar/manual]
    
    Boot <-->|Spring Data JPA| DB[(MySQL Database)]
Loading

์•„ํ‚คํ…์ฒ˜ ํ†ต์‹  ํ๋ฆ„

  1. ๋ชจ๋ฐ”์ผ ํด๋ผ์ด์–ธํŠธ (Flutter): ์˜ค๋””์˜ค ๋ฐ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ REST API ํ˜•ํƒœ๋กœ ์š”์ฒญํ•˜๋ฉฐ JWT ํ† ํฐ์„ ํ—ค๋”์— ์‹ค์–ด ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ (Spring Boot): ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๊ณ , ์Œ์„ฑ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋ณต์žกํ•œ ์ž‘์—…์ธ ๊ฒฝ์šฐ Spring WebFlux WebClient๋ฅผ ํ™œ์šฉํ•˜์—ฌ FastAPI AI ์„œ๋ฒ„๋กœ ์˜ค๋””์˜ค ํŒŒ์ผ์„ ๋น„๋™๊ธฐ(Non-blocking Mono) ๋ฐฉ์‹์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. AI ์„œ๋ฒ„ (FastAPI): ์ „๋‹ฌ๋ฐ›์€ ์˜ค๋””์˜ค๋ฅผ ์ „์ฒ˜๋ฆฌํ•œ ๋’ค, ๊ตฌ์Œ์žฅ์• (Dysarthria) ํŒŒ์ธํŠœ๋‹ Whisper์— ํ†ต๊ณผ์‹œ์ผœ ๋‚ ๊ฒƒ์˜ ํ…์ŠคํŠธ(Raw Text)๋ฅผ ์ „์‚ฌํ•ฉ๋‹ˆ๋‹ค.
  4. LLM ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ (AWS Bedrock): ์ „์‚ฌ๋œ ํ…์ŠคํŠธ๋ฅผ Claude 3 Haiku ํ”„๋กฌํ”„ํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ์ •์ค‘ํ•˜๊ณ  ์™„์„ฑ๋„ ๋†’์€ ๋น„์ฆˆ๋‹ˆ์Šค์šฉ ๋ฌธ์žฅ(Refined Text)์œผ๋กœ ์ •์ œํ•˜๊ฑฐ๋‚˜, ์—…๋ฌด ํšŒ์˜ ๋ถ„์„ ๋ฐ์ดํ„ฐ(์š”์•ฝ, ํ•  ์ผ, ์ผ์ •)๋ฅผ ์ถ”์ถœํ•ด JSON ๊ฐ์ฒด๋กœ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค.
  5. ์บ˜๋ฆฐ๋” ๋™๊ธฐํ™”: AI ๋ถ„์„ ๊ณผ์ •์—์„œ ์ผ์ • ์ •๋ณด๊ฐ€ ์ถ”์ถœ๋˜๋ฉด, AI ์„œ๋ฒ„๊ฐ€ ์ฆ‰์‹œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์˜ ์ˆ˜๋™ ์ผ์ • ์ƒ์„ฑ API(POST /api/calendar/manual)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ์บ˜๋ฆฐ๋”์— ์ž๋™ ์—ฐ๋™ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ ํ•ต์‹ฌ ๊ธฐ์ˆ  ์Šคํƒ ๋ฐ ์ฑ„ํƒ ์ด์œ  (Tech Stack & Rationale)

1. Spring Boot Backend Services (Java)

  • Java 21 & Spring Boot 3.2.4
    • ๋Œ€๊ทœ๋ชจ ์Šค๋ ˆ๋“œ ๋™์‹œ์„ฑ ์ƒํ™ฉ์—์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ(Virtual Threads)์˜ ์—ฐ๋™์„ฑ๊ณผ ์ตœ์‹  JVM ์„ฑ๋Šฅ ์ด์ ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด Java 21 LTS ๋ฒ„์ „ ์ฑ„ํƒ.
  • Spring WebFlux WebClient
    • ์Œ์„ฑ ์ „์‚ฌ(ASR) ๋ฐ LLM ์ฒ˜๋ฆฌ ๊ณผ์ •์€ ํ•„์—ฐ์ ์œผ๋กœ 5~15์ดˆ ์ˆ˜์ค€์˜ ๋†’์€ ์ง€์—ฐ ์‹œ๊ฐ„(Latency)์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด MVC์˜ RestTemplate ๊ฐ™์€ ๋™๊ธฐ์‹ ๋™ํ‚น ํ†ต์‹ ์€ ๋Œ€๋Ÿ‰์˜ ์˜ค๋””์˜ค ์ „์†ก ์‹œ ์„œ๋ธ”๋ฆฟ ์Šค๋ ˆ๋“œ ๊ณ ๊ฐˆ์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์˜ˆ๋ฐฉํ•˜๊ณ  ๊ทน๋„๋กœ ๊ฒฝ๋Ÿ‰ํ™”๋œ ๋น„๋™๊ธฐ ๋…ผ๋ธ”๋กœํ‚น ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•ด WebClient ์ฑ„ํƒ.
  • Spring Security, OAuth2 Client, JJWT (0.11.5)
    • ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ(Flutter)์ด๋ฏ€๋กœ ์„ธ์…˜ ๋Œ€์‹  ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š” Stateless ํ† ํฐ ๊ธฐ๋ฐ˜(JWT) ์ธ์ฆ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ๊ตฌ๊ธ€, ์นด์นด์˜ค ๋“ฑ์˜ ์†Œ์…œ ๊ฐ„ํŽธ ์—ฐ๋™์„ ์‹ ์†ํžˆ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ง ํ‘œ์ค€ OAuth2 ํด๋ผ์ด์–ธํŠธ ํ†ตํ•ฉ.
  • Spring Data JPA & MySQL
    • ๊ฐ์ฒด ์ง€ํ–ฅ์  ์—”ํ‹ฐํ‹ฐ ์„ค๊ณ„์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(1์ฐจ ์บ์‹œ, ์“ฐ๊ธฐ ์ง€์—ฐ)๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜ ๋ฌด๊ฒฐ์„ฑ๊ณผ ํšจ์œจ์ ์ธ ๋„๋ฉ”์ธ ๋ชจ๋ธ ๊ด€๋ฆฌ ๋ณด์žฅ.

2. AI & Speech Engine (Python)

  • FastAPI & Uvicorn
    • Python ๊ธฐ๋ฐ˜์˜ ๊ณ ์„ฑ๋Šฅ ๋น„๋™๊ธฐ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, ๋ฉ€ํ‹ฐํŒŒํŠธ ์˜ค๋””์˜ค ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐ์ดํ„ฐ์™€ AI ์ถ”๋ก  ๋ฃจํ”„๋ฅผ ๋†’์€ ์ฒ˜๋ฆฌ๋Ÿ‰์œผ๋กœ ์„œ๋น™ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ.
  • Fine-Tuned ASR Whisper (openai/whisper-medium ๊ธฐ๋ฐ˜)
    • ์ผ๋ฐ˜์ ์ธ ์ƒ์šฉ STT๋Š” ๋ถˆ๋ถ„๋ช…ํ•œ ์กฐ์Œ(Stammering, Dysarthria)์„ ์†Œ์Œ์ด๋‚˜ ์˜ค๋ฐœ์Œ์œผ๋กœ ์น˜๋ถ€ํ•˜์—ฌ ์ธ์‹๋ฅ ์ด ๊ทน๋„๋กœ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณด์™„ํ•˜๊ณ ์ž ํ•œ๊ตญ์–ด ๊ตฌ์Œ์žฅ์•  ์Œ์„ฑ ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ๋ฏธ์„ธ ์กฐ์ •๋œ ๋ชจ๋ธ(tepo6640/whisper-dysarthria-ko)์„ Transformers Pipeline ํ˜•ํƒœ๋กœ ๋กœ๋“œํ•˜์—ฌ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • librosa ์˜ค๋””์˜ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ์ž…๋ ฅ ์Œ์›์„ 16,000Hz, ๋ชจ๋…ธ ์ฑ„๋„๋กœ ๋ฆฌ์ƒ˜ํ”Œ๋งํ•˜์—ฌ ์ถ”๋ก  ์˜ค์ฐจ ์ตœ์†Œํ™”.
    • ๋‹ค์ค‘ ์˜ค๋””์˜ค์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด batch_size=8, stride_length_s=5, ๊ทธ๋ฆฌ๊ณ  ๋ฐ˜๋ณต์ ์ด๊ณ  ๊ผฌ์ด๋Š” ๋ฐœ์Œ์— ๊ฐ•์ธํ•˜๋„๋ก repetition_penalty=1.1 ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋งž์ถค ๊ตฌ์„ฑ.
  • AWS Bedrock (Claude 3 Haiku)
    • Whisper์˜ ์ „์‚ฌ ํ…์ŠคํŠธ ์† ์–ธ์–ด์  ์˜ค๋ฅ˜๋ฅผ ๊ทน๋ณตํ•˜๊ณ , ์ •๊ตํ•˜๊ณ  ๊ณต์†ํ•œ ๋ฌธ๋งฅ์„ ์™„์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ€์„ฑ๋น„์™€ ๋งค์šฐ ๋น ๋ฅธ ์‘๋‹ต ์‹œ๊ฐ„(Latency)์„ ๋ณด์œ ํ•œ Claude 3 Haiku API ๋ชจ๋ธ์„ ์ ์šฉํ•˜์—ฌ ์ผ์ƒ ๋ฐ ์ง์—…์  ๋ฐœํ™” ๋ถ„์„ ๊ธฐ๋Šฅ ๊ตฌ๋™.

๐Ÿ” ๊ธฐ์ˆ ์  ์‹ฌ์ธต ๋ถ„์„ (Deep Dive)

1. Spring WebFlux ๋ฆฌ์•กํ‹ฐ๋ธŒ ๋น„๋™๊ธฐ AI ์ธํ„ฐํŽ˜์ด์Šค ์—ฐ๋™

๋ฐฑ์—”๋“œ์™€ AI ์„œ๋ฒ„๋Š” ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์œผ๋ฉฐ ์Šคํ”„๋ง์˜ WebClient๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ˜์‘ํ˜• ๋น„๋™๊ธฐ ๋‹จ์ผ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

// RemasteringService.java ์ค‘ ์ผ๋ถ€ ๋ฐœ์ทŒ
public Mono<RemasteringLogResponse> remaster(String email, MultipartFile audioFile, String preferredTone) {
    long startTime = System.currentTimeMillis();

    MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
    bodyBuilder.part("file", audioFile.getResource());
    if (preferredTone != null && !preferredTone.isBlank()) {
        bodyBuilder.part("preferred_tone", preferredTone);
    }

    return webClient.post()
            .uri("/api/analyze")
            .contentType(MediaType.MULTIPART_FORM_DATA)
            .body(BodyInserters.fromMultipartData(bodyBuilder.build()))
            .retrieve()
            .bodyToMono(AiServerResponseDto.class)
            .map(aiRes -> {
                long latency = System.currentTimeMillis() - startTime;
                String raw = aiRes.getRawText() != null ? aiRes.getRawText() : "์ธ์‹ ๋‚ด์šฉ ์—†์Œ";
                String refined = aiRes.getRefinedText() != null ? aiRes.getRefinedText() : raw;
                
                // ํ†ต๊ณ„ ๋ˆ„์  ๋ฐ ๋น„๋™๊ธฐ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ฒ˜๋ฆฌ
                userService.addCorrection(email, 50);
                ConversationLog savedLog = conversationService.saveResult(email, raw, refined, latency);

                return new RemasteringLogResponse(savedLog.getLogId(), savedLog.getSttOrigin(), savedLog.getRefinedText(), (int) latency);
            });
}
  • ๋™์ž‘ ์›๋ฆฌ: ์‚ฌ์šฉ์ž๊ฐ€ ์ „์†กํ•œ ๋ฐ์ดํ„ฐ๋Š” ์ŠคํŠธ๋ฆผ ํ˜•์‹์œผ๋กœ AI ์„œ๋ฒ„์— ์ „์†ก๋˜๋ฉฐ, ์ฒ˜๋ฆฌ ์ง€์—ฐ ์‹œ๊ฐ„์ด ์œ ์ง€๋˜๋Š” ๋™์•ˆ ๋ฐฑ์—”๋“œ ํ”„๋กœ์„ธ์Šค์˜ ์Šค๋ ˆ๋“œ๋Š” ํ’€๋กœ ๋ฐ˜ํ™˜๋˜์–ด ๋Œ€๊ธฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ›์„ ๋•Œ ๋น„๋กœ์†Œ ๋งคํ•‘ ์ž‘์—…๊ณผ DB ์ €์žฅ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋ฏ€๋กœ ์„œ๋ฒ„ ์ž์›์˜ ํšจ์œจ์„ฑ์ด ํš๋“๋ฉ๋‹ˆ๋‹ค.

2. ASR + LLM ๋‹ค๋‹จ๊ณ„ ๋ฌธ์žฅ ๊ต์ • ์•„ํ‚คํ…์ฒ˜

๊ตฌ์Œ์žฅ์•  ์•„๋™ ๋ฐ ์„ฑ์ธ์˜ ๋Œ€ํ™” ํŠน์ง•์€ ๋‹จ์–ด ๋ฐ˜๋ณต, ๋ชจ์Œ ์™œ๊ณก, ์ž์Œ ๋ˆ„๋ฝ์ž…๋‹ˆ๋‹ค. AI ์„œ๋ฒ„๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด 2๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ต๊ณผ์‹œํ‚ต๋‹ˆ๋‹ค.

# 1๋‹จ๊ณ„: Custom ASR (Whisper)๋ฅผ ํ†ตํ•œ ์Œ์„ฑ ์ „์‚ฌ
raw_text = transcribe_audio(asr_pipe, audio_path)

# 2๋‹จ๊ณ„: AWS Bedrock LLM์„ ํ†ตํ•œ Contextual Refinement
# Prompt Engineering์„ ํ†ตํ•ด ๋น„๋…ผ๋ฆฌ์  ์ „์‚ฌ๋ฅผ ๋ฌธ๋งฅ์— ๋งž๋Š” ๋น„์ฆˆ๋‹ˆ์Šค์  ๊ตฌ์–ด๋กœ ์น˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
prompt = f"""
You are the "Malbit Smart Workplace Assistant," specialized in supporting workers with speech or language impairments.
Analyze the [Transcript] below and refine it to clear, polite Korean.
Ensure immediate action items (checklists) and schedules are properly structured.
Reference Date: {current_date}
"""

์ด 2๋‹จ๊ณ„ ๋ณด์ • ํŒŒ์ดํ”„๋ผ์ธ์€ ๊ตฌ์Œ์žฅ์•  ์Œ์„ฑ์ธ์‹ ์ •ํ™•๋„์˜ ํƒœ์ƒ์  ๋ถˆํ™•์‹ค์„ฑ์„ LLM ๋ฌธ๋งฅ ๋ณต์›๋ ฅ์œผ๋กœ ๋ณด์ •ํ•˜์—ฌ ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฐ ์†Œํ†ต ํ˜„์žฅ์—์„œ ๊ฐ•๋ ฅํ•œ ์‹ค์šฉ์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

3. ๋‹คํ˜•์„ฑ(Polymorphic) ์—…๋ฌด ๋ถ„์„ ๋ฐ ๋กœ๊ทธ ์ €์žฅ ์•„ํ‚คํ…์ฒ˜

ํšŒ์˜ ๋‚ด์šฉ๊ณผ ์žฅ๋ฌธ ๋ฐœํ™” ๋ฐ์ดํ„ฐ ๋ถ„์„ ์‹œ ๋Œ€๋Ÿ‰์˜ ๋‹คํ˜•์„ฑ ํ…์ŠคํŠธ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๋ถ„๋ฅ˜ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด Log ์—”ํ‹ฐํ‹ฐ์™€ ์ƒํ˜ธ ์—ฐ๊ด€๋œ LogDetail ์—”ํ‹ฐํ‹ฐ ๊ตฌ์กฐ๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

  • Log: ์ „์‚ฌ ์„ธ์…˜์— ๋Œ€ํ•œ ๊ณ ์œ  ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(ํƒ€์ดํ‹€, ์ผ์ž, ์‹œ์ž‘ ์‹œ๊ฐ„, ์ƒํƒœ, ์„ธ์…˜ ์†Œ์œ ์ฃผ) ๊ด€๋ฆฌ.
  • LogDetail: ๋‹คํ˜•์„ฑ ํƒ€์ž… ํ•„๋“œ(DetailType)๋ฅผ ํ™œ์šฉํ•ด ํ•˜๋‚˜์˜ ์Œ์„ฑ ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ๋‚˜์˜จ ๋ณตํ•ฉ์ ์ธ AI ๊ฐ€๊ณต ์ •๋ณด๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌ์กฐํ™” ๋ฐ ๋งคํ•‘.
    • SUMMARY: ํšŒ์˜์˜ ์ค‘์  ์ฃผ์ œ ๋ฐ AI ๋‹จ๋ฌธ ์š”์•ฝ๋ณธ.
    • DECISION: ํšŒ์˜ ์ค‘ ๊ตฌ๋‘๋กœ ํ™•์ •๋œ ๋น„์ •๊ธฐ์  ํ•ฉ์˜์•ˆ ๋ฐ ์ฒดํฌ๋ฆฌ์ŠคํŠธ.
    • TODO: ์ผ์ •(์‹œ์ž‘์ผ, ๋งˆ๊ฐ์ผ, ์ง๋ฌด ์นดํ…Œ๊ณ ๋ฆฌ)์œผ๋กœ ํ™˜์‚ฐ๋  ์ˆ˜ ์žˆ๋Š” ์„ธ๋ถ€์ ์ธ ์‹ค๋ฌด ๋ชฉ๋ก.

๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ERD (Database Entity Relationship Diagram)

erDiagram
    USER ||--|| USER_STATISTICS : "has"
    USER ||--o{ LOG : "creates"
    LOG ||--o{ LOG_DETAIL : "contains"
    USER ||--o{ TRAINING_SESSION : "conducts"
    TRAINING_SESSION ||--o{ STEP_RESULT : "produces"
    SCENARIO_STEP ||--o{ STEP_RESULT : "evaluates"
    USER ||--o{ TASK : "manages"

    USER {
        Long id PK
        String email UK
        String password
        String name
        DisabilityType disabilityType
        CognitiveLevel cognitiveLevel
        JobType jobType
    }
    USER_STATISTICS {
        Long id PK
        Long userId FK
        int totalCorrectionCount
        int totalSummaryCount
        int totalRoleplayCount
    }
    LOG {
        Long id PK
        Long userId FK
        String title
        LocalDate date
        LocalTime startTime
        String duration
        LogType type
    }
    LOG_DETAIL {
        Long id PK
        Long logId FK
        String content
        DetailType type
        String assignee
    }
    TRAINING_SESSION {
        Long id PK
        Long userId FK
        Long categoryId FK
        Long currentStepId FK
        SessionStatus status
    }
    SCENARIO_STEP {
        Long id PK
        Long categoryId FK
        int stepOrder
        String currentSituation
        String guestScript
        String hintText
        String missionText
        String retryScript
    }
    STEP_RESULT {
        Long id PK
        Long sessionId FK
        Long stepId FK
        String rawText
        String refinedText
        int score
        boolean isPassed
    }
    TASK {
        Long id PK
        Long userId FK
        String content
        String category
        LocalDateTime startAt
        LocalDateTime endAt
        boolean isCompleted
    }
Loading

๐Ÿ”Œ ์ฃผ์š” API ์—”๋“œํฌ์ธํŠธ ๋ช…์„ธ (Core APIs)

1. ๋ฆฌ๋งˆ์Šคํ„ฐ๋ง ๋ฐ ํšŒ์˜ ๋ถ„์„ API (Async / Non-blocking)

  • POST /api/remaster

    • ์„ค๋ช…: ๋‹จ๋ฌธ ์Œ์„ฑ ๋…น์Œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜์—ฌ ๊นจ๋—ํ•˜๊ณ  ๊ณต์†ํ•œ ๋ฌธ์žฅ์œผ๋กœ ๋ฆฌ๋งˆ์Šคํ„ฐ๋ง์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ณด์•ˆ: Bearer JWT ํ† ํฐ ํ•„์ˆ˜
    • Form Data:
      • audio_file: MultipartFile (์Œ์„ฑ ๋ฐ์ดํ„ฐ)
      • preferred_tone: String (์›ํ•˜๋Š” ๋งํˆฌ ํ•„ํ„ฐ - ์„ ํƒ)
    • Response: RemasteringLogResponse (๋กœ๊ทธ ID, STT ์›๋ฌธ, ๋ณด์ • ๋ฌธ์žฅ, ์†Œ์š”์‹œ๊ฐ„)
  • POST /api/remaster/analyze-meeting

    • ์„ค๋ช…: ์žฅ๋ฌธ ํšŒ์˜ ๋…น์Œ์„ ์—…๋กœ๋“œํ•˜์—ฌ ํ…์ŠคํŠธ ์š”์•ฝ, ๊ฒฐ์ •์‚ฌํ•ญ, ๋‹ค๊ฐ€์˜ค๋Š” ํ•  ์ผ์„ ์ถ”์ถœํ•˜๊ณ  ๋ฐฑ์—”๋“œ ์บ˜๋ฆฐ๋”์— ์—ฐ๋™ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ณด์•ˆ: Bearer JWT ํ† ํฐ ํ•„์ˆ˜
    • Form Data:
      • audio_file: MultipartFile
    • Response: MeetingAnalysisResponse (๋กœ๊ทธ ID, ์ „์ฒด ํ…์ŠคํŠธ ์›๋ฌธ, ์š”์•ฝ, ์ถ”์ถœ๋œ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ๋ฐฐ์—ด, ์บ˜๋ฆฐ๋” ์—ฐ๋™ ์ผ์ • ๋ฐฐ์—ด)

2. ๋ฐœ์Œ ํ›ˆ๋ จ (์ƒํ™ฉ๊ทน) API

  • GET /api/training/categories
    • ์„ค๋ช…: ํ›ˆ๋ จ ๊ฐ€๋Šฅํ•œ ์ง๋ฌด ์ƒํ™ฉ๊ทน(์นดํŽ˜, ํŽธ์˜์  ๋“ฑ)์˜ ๋ชฉ๋ก์„ ์ „์ฒด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • POST /api/training/start
    • ์„ค๋ช…: ํŠน์ • ์ง๋ฌด ์นดํ…Œ๊ณ ๋ฆฌ์˜ ํ›ˆ๋ จ ์„ธ์…˜์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. (์ฒซ ๋‹จ๊ณ„ ์‹œ๋‚˜๋ฆฌ์˜ค ๋Œ€๋ณธ ๋ฐ˜ํ™˜)
    • Body: { "categoryId": Long }
  • POST /api/training/analyze-voice
    • ์„ค๋ช…: ์‚ฌ์šฉ์ž์˜ ์‹ค์‹œ๊ฐ„ ๋ง์†Œ๋ฆฌ ๋…น์Œ ํŒŒ์ผ์„ ์ „์‚ฌ ๋ฐ ๋ถ„์„ํ•˜์—ฌ ์ •๋‹ต ์‹œ๋‚˜๋ฆฌ์˜ค ๋Œ€์‚ฌ์™€์˜ ์œ ์‚ฌ์„ฑ์„ ์ฑ„์ ํ•˜๊ณ , ํ†ต๊ณผ(70์ ) ์‹œ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๋™์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • Form Data: audio_file (Multipart), sessionId (Parameter)
  • POST /api/training/finish/{sessionId}
    • ์„ค๋ช…: ์ƒํ™ฉ๊ทน ์—ฐ์Šต์„ ์ •์‹ ์ข…๋ฃŒํ•˜๊ณ , ์ง„ํ–‰๋œ ๋ชจ๋“  ์„ธ๋ถ€ ํ‰๊ฐ€ ๊ธฐ๋ก๊ณผ ์ข…ํ•ฉ ์ ์ˆ˜ ๋ฐ ์ตœ์ข… ์ดํ‰์„ ์ƒ์„ฑํ•˜์—ฌ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

3. ์บ˜๋ฆฐ๋” ๋ฐ ์ผ์ • ๊ด€๋ฆฌ API

  • POST /api/calendar/manual
    • ์„ค๋ช…: ์ƒˆ๋กœ์šด ์ผ์ •์„ ์บ˜๋ฆฐ๋”์— ์ˆ˜๋™์œผ๋กœ ์ง์ ‘ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. (AI ์„œ๋ฒ„์—์„œ ํŒŒ์‹ฑ๋œ ์ผ์ •๋„ ์ด ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.)
    • Body: { "content": "string", "category": "string", "start_at": "YYYY-MM-DD HH:MM:SS", "end_at": "YYYY-MM-DD HH:MM:SS" }
  • GET /api/calendar
    • ์„ค๋ช…: ํŠน์ • ๋‚ ์งœ ๊ธฐ์ค€์˜ ์ฃผ๊ฐ„/์›”๊ฐ„ ์ผ์ •์„ ๋ชจ๋‘ ์Šค์บ”ํ•˜์—ฌ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
    • Query Param: query_date (์˜ˆ: 2026-05-27)

โš™๏ธ ์ธํ”„๋ผ ๋ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • (Configuration Guide)

1. Spring Boot ๋ฐฑ์—”๋“œ ์„ค์ • (malbit_backend/.env)

๋ฐฑ์—”๋“œ ๊ตฌ๋™์— ํ•„์ˆ˜์ ์ธ ์ฃผ์š” ๋กœ์ปฌ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค:

DB_URL=jdbc:mysql://localhost:3306/malbit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul
DB_USERNAME=your_mysql_username
DB_PASSWORD=your_mysql_password

# JWT ์•”ํ˜ธํ™” ๋Œ€์นญํ‚ค ์„ค์ • (32์ž ์ด์ƒ์˜ ๊ฐ•๋„ ๋†’์€ ํ‚ค)
JWT_SECRET=your_jwt_signature_secret_key_strong_and_unique

# Social OAuth2 Credentials
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
KAKAO_CLIENT_ID=your_kakao_client_id
KAKAO_CLIENT_SECRET=your_kakao_client_secret

# AI ์„œ๋ฒ„ Endpoint ์ฃผ์†Œ
AI_SERVER_URL=http://localhost:5000

2. FastAPI AI ์„œ๋ฒ„ ์„ค์ • (malbit_backend/malbit_ai/.env)

# AWS Bedrock access keys for Claude-3-Haiku API invocation
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key

# ๊ธฐ๋ณธ ๋Œ€ํ™” ๋ณด์ • ๋ชจ๋ธ ์„ค์ •
LLM_MODEL=anthropic.claude-3-haiku-20240307-v1:0

# ํŒŒ์ธํŠœ๋‹ Whisper ๋กœ๋“œ ํ˜น์€ standard ๊ฐ€์ค‘์น˜ ๊ฒฝ๋กœ
MODEL_PATH=openai/whisper-medium

# Spring Boot ์„œ๋ฒ„ Endpoint
BACKEND_URL=http://localhost:8080

๐Ÿš€ ๋กœ์ปฌ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ๋ฐฉ๋ฒ• (How to Run)

ํ•„์ˆ˜ ์ธํ”„๋ผ ํ™˜๊ฒฝ

  • Java 21 JDK ์ด์ƒ
  • Python 3.9 ์ด์ƒ
  • FFmpeg ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: ์Œ์›์˜ ๋ณ€ํ™˜ ๋ฐ ๋””์ฝ”๋”ฉ ์—ฐ์‚ฐ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด OS ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ํ•„์ˆ˜์ ์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • MacOS: brew install ffmpeg
    • Windows: choco install ffmpeg ํ˜น์€ ์ˆ˜๋™ ๋‹ค์šด๋กœ๋“œ ํ›„ Path ์ถ”๊ฐ€

1. Spring Boot ๋นŒ๋“œ & ์‹คํ–‰

cd malbit_backend

# ์˜์กด์„ฑ ๋นŒ๋“œ (ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํŒจ์Šค ์˜ต์…˜)
./gradlew build -x test

# ์‹คํ–‰ํ˜• Jar ๊ตฌ๋™
java -jar build/libs/demo-0.0.1-SNAPSHOT.jar

2. FastAPI AI ์„œ๋ฒ„ ์‹คํ–‰

cd malbit_backend/malbit_ai

# ๊ฐ€์ƒํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๋ฐ ํŒจํ‚ค์ง€ ์„ค์ •
python -m venv venv
source venv/Scripts/activate  # Windows: .\venv\Scripts\activate

# ์˜์กด ๋ชจ๋“ˆ ์ „์ฒด ์„ค์น˜
pip install -r requirements.txt

# FastAPI ์„œ๋ฒ„ 5000ํฌํŠธ๋กœ ์‹คํ–‰
uvicorn app:app --host 0.0.0.0 --port 5000 --reload

3. Docker๋ฅผ ํ™œ์šฉํ•œ ์ปจํ…Œ์ด๋„ˆ๋ผ์ด์ง• ๋ฐฐํฌ

๋ณธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋‚ด์˜ Dockerfile๋“ค์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์ค‘ ๊ฒฉ๋ฆฌ ๋ฐฐํฌ ํ™˜๊ฒฝ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# 1. Spring Boot ๋ฐฑ์—”๋“œ ์ปจํ…Œ์ด๋„ˆ ๋นŒ๋“œ & ์‹คํ–‰
cd malbit_backend
docker build -t malbit-backend:latest .
docker run -d -p 8080:8080 --env-file .env malbit-backend:latest

# 2. AI ์„œ๋ฒ„ GPU ๊ฐ€์† ๋ฐฐํฌ (GPU ๋ณด์œ  ์ธ์Šคํ„ด์Šค ์ „์ œ)
cd malbit_ai
docker build -t malbit-ai:latest .
docker run -d -p 5000:5000 --gpus all --env-file .env malbit-ai:latest

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages