๐ STT/TTS ์ฑ๋ฅ ์ ํ ์์ธ ๋ถ์ ์๋ฃ
๋ ํ๋ก์ ํธ๋ฅผ ๋น๊ตํ ๊ฒฐ๊ณผ, ์ฑ๋ฅ ์ ํ์ ์ฃผ์ ์์ธ์ ์ฐพ์์ต๋๋ค.
๐ ํต์ฌ ์ฐจ์ด์ ๋น๊ต
| ํญ๋ชฉ | ๊ธฐ์กด () | ์ ๋ฒ์ () |
|---|---|---|
| TTS ๋ฐฉ์ | Android TextToSpeech (๋ก์ปฌ) | OpenAI TTS API (๋คํธ์ํฌ) |
| LLM ํธ์ถ | 1ํ (์ง๋ฌธโ์๋ต) | 1~2ํ (์ง๋ฌธโ์๋ต + CAGE ์์ฝ) |
| Context ์ฒ๋ฆฌ | RAG๋ง | RAG + CAGE (๋ํ ๊ธฐ๋ก) |
| ์ค๋์ค ์ฒ๋ฆฌ | ์ฆ์ ์ฌ์ | ํ์ผ ์ ์ฅ ํ MediaPlayer ์ฌ์ |
๐จ ์ฑ๋ฅ ์ ํ ์์ธ (Step-by-Step)
1. TTS ๋คํธ์ํฌ ์ง์ฐ (๊ฐ์ฅ ํฐ ์์ธ)
๊ธฐ์กด: speak() โ Android TTS โ ์ฆ์ ์ฌ์ (50~100ms)
์๋ฒ์ : speak() โ OpenAI API ํธ์ถ โ ์ค๋์ค ๋ค์ด๋ก๋ โ ํ์ผ ์ ์ฅ โ MediaPlayer ์ฌ์ (1~3์ด)
2. CAGE ์์ฝ์ผ๋ก ์ธํ ์ถ๊ฐ API ํธ์ถ
// ๋ํ๊ฐ 10๊ฐ ์ด๊ณผ ์ ์๋์ผ๋ก ์์ฝ API ํธ์ถ
suspend fun summarizeOldConversations() {
openAIService.summarizeConversations(conversationTexts) // ์ถ๊ฐ API ํธ์ถ!
}
3. ๋ ๋ง์ Context ์ ์ก
// ๋งค ์์ฒญ๋ง๋ค RAG + CAGE ์ปจํ
์คํธ ๊ฒฐํฉ
val combinedContext = buildString {
append("์ฐธ๊ณ ๋ฌธ์:\n$ragContext\n\n") // RAG
append(cageContext) // + ๋ํ ๊ธฐ๋ก ์ ์ฒด
}
4. ๋๊ธฐ์ ํ์ผ I/O
// TTS ์ค๋์ค๋ฅผ ํ์ผ๋ก ์ ์ฅ ํ ์ฌ์
FileOutputStream(tempFile).use { fos ->
fos.write(audioBytes) // ํ์ผ ์ฐ๊ธฐ ์ง์ฐ
}
mediaPlayer.setDataSource(tempFile.absolutePath)
mediaPlayer.prepare() // ๋๊ธฐ prepare
โก ํด๊ฒฐ ๋ฐฉ์
์ฆ์ ์ ์ฉ ๊ฐ๋ฅํ ์ต์ ํ:
- TTS ์บ์ฑ ์ถ๊ฐ – ๋์ผ ํ ์คํธ ์ฌ์์ฒญ ๋ฐฉ์ง
- Streaming TTS ์ฌ์ฉ –
tts-1๋์ ์คํธ๋ฆฌ๋ฐ์ผ๋ก ์ ์ง์ ์ฌ์ - prepareAsync() ์ฌ์ฉ – ๋๊ธฐ prepare โ ๋น๋๊ธฐ๋ก ๋ณ๊ฒฝ
- CAGE ์์ฝ ๋น๋๊ธฐํ – ์๋ต ํ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์์ฝ
๐ ์์ฑ๋ ํ์ผ
| ํ์ผ | ์ฃผ์ ์ต์ ํ |
|---|---|
OpenAITTSService_optimized.kt | LRU ์บ์ (10MB), OkHttp ํ์์์, Connection Pool |
SpeechManager_optimized.kt | prepareAsync(), AudioAttributes, ์์ํ์ผ ์๋์ ๋ฆฌ |
CAGEManager_optimized.kt | ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ฝ, ๋๊ธฐ ์ปจํ ์คํธ ์กฐํ |
DashboardViewModel_optimized.kt | ์ปจํ ์คํธ ํฌ๊ธฐ ์ ํ, ๋น๋๊ธฐ ๋ํ ์ถ๊ฐ |
README_OPTIMIZATION.md | ์ ์ฉ ๋ฐฉ๋ฒ ๋ฐ ํ ์คํธ ๊ฐ์ด๋ |
โก ์์ ์ฑ๋ฅ ๊ฐ์
| ์ํฉ | ๊ธฐ์กด | ์ต์ ํ ํ |
|---|---|---|
| TTS ์ฒซ ์ฌ์ | 2~3์ด | 1.5~2์ด |
| TTS ์บ์ ํํธ | 2~3์ด | 50~100ms |
| CAGE ์์ฝ ๋๊ธฐ | 1~2์ด | 0ms (๋ฐฑ๊ทธ๋ผ์ด๋) |
๋ต๊ธ ๋จ๊ธฐ๊ธฐ