diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index e8f2071..907c5d9 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -77,19 +77,19 @@ fun main() = application { LaunchedEffect(Unit) { // NewsService나 KisTradeService에서 사용하는 client를 전달 - DartCodeManager.updateCorpCodes(HttpClient(CIO) { - install(ContentNegotiation) { - json(Json { - ignoreUnknownKeys = true - encodeDefaults = true // 기본값이 포함된 요청 바디를 정확히 전송하기 위해 필요 - }) - } - // [수정] 모든 로그(Headers + Body)를 찍도록 설정 - install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.BODY - } - }) +// DartCodeManager.updateCorpCodes(HttpClient(CIO) { +// install(ContentNegotiation) { +// json(Json { +// ignoreUnknownKeys = true +// encodeDefaults = true // 기본값이 포함된 요청 바디를 정확히 전송하기 위해 필요 +// }) +// } +// // [수정] 모든 로그(Headers + Body)를 찍도록 설정 +// install(Logging) { +// logger = Logger.DEFAULT +// level = LogLevel.BODY +// } +// }) } // 앱 실행 시 필요한 바이너리 경로 (실행 파일 위치) val binPath = getLlamaBinPath() @@ -113,6 +113,9 @@ fun main() = application { vtsAppKey = it[ConfigTable.vtsAppKey], vtsSecretKey = it[ConfigTable.vtsSecretKey], vtsAccountNo = it[ConfigTable.vtsAccountNo], + nAppKey = it[ConfigTable.nAppKey], + nSecretKey = it[ConfigTable.nSecretKey], + dAppKey = it[ConfigTable.dAppKey], isSimulation = it[ConfigTable.isSimulation], htsId = it[ConfigTable.htsId], modelPath = it[ConfigTable.modelPath], @@ -150,6 +153,7 @@ fun main() = application { AppScreen.Settings -> { SettingsScreen( onAuthSuccess = { + // 2. 설정 및 인증 완료 시점의 처리 val config = KisSession.config AutoTradingManager.isSystemReadyToday = true diff --git a/src/main/kotlin/database/DatabaseFactory.kt b/src/main/kotlin/database/DatabaseFactory.kt index efcbb2b..7ebdd55 100644 --- a/src/main/kotlin/database/DatabaseFactory.kt +++ b/src/main/kotlin/database/DatabaseFactory.kt @@ -26,6 +26,11 @@ object ConfigTable : Table("app_config") { val vtsAppKey = varchar("vts_app_key", 255).default("") val vtsSecretKey = varchar("vts_secret_key", 255).default("") val vtsAccountNo = varchar("vts_account_no", 20).default("") + + val nAppKey = varchar("naver_app_key", 255).default("") + val nSecretKey = varchar("naver_secret_key", 255).default("") + val dAppKey = varchar("dart_api_key", 255).default("") + val isSimulation = bool("is_simulation").default(true) val modelPath = varchar("model_path", 512).default("") val embedModelPath = varchar("embed_model_path", 512).default("") @@ -207,6 +212,9 @@ object DatabaseFactory { vtsAppKey = it[ConfigTable.vtsAppKey], vtsSecretKey = it[ConfigTable.vtsSecretKey], vtsAccountNo = it[ConfigTable.vtsAccountNo], + nAppKey = it[ConfigTable.nAppKey], + nSecretKey = it[ConfigTable.nSecretKey], + dAppKey = it[ConfigTable.dAppKey], htsId = it[ConfigTable.htsId], isSimulation = it[ConfigTable.isSimulation], // htsId 로드 modelPath = it[ConfigTable.modelPath], @@ -243,6 +251,9 @@ object DatabaseFactory { it[vtsSecretKey] = config.vtsSecretKey it[realAccountNo] = config.realAccountNo it[vtsAccountNo] = config.vtsAccountNo + it[ConfigTable.nAppKey] = config.nAppKey + it[ConfigTable.nSecretKey] = config.nSecretKey + it[ConfigTable.dAppKey] = config.dAppKey it[isSimulation] = config.isSimulation it[htsId] = config.htsId it[modelPath] = config.modelPath diff --git a/src/main/kotlin/model/AppConfig.kt b/src/main/kotlin/model/AppConfig.kt index 72da7bf..a414b8e 100644 --- a/src/main/kotlin/model/AppConfig.kt +++ b/src/main/kotlin/model/AppConfig.kt @@ -44,6 +44,11 @@ data class AppConfig( val vtsSecretKey: String = "", val vtsAccountNo: String = "", + // 모의 3종 + val nAppKey: String = "", + val nSecretKey: String = "", + val dAppKey: String = "", + // [세션 데이터 - 메모리에서만 관리] var marketToken: String = "", var marketTokenExpiredAt: LocalDateTime? = null, // 만료 시간 추가 diff --git a/src/main/kotlin/network/DartCodeManager.kt b/src/main/kotlin/network/DartCodeManager.kt index 3a5a4d9..820598b 100644 --- a/src/main/kotlin/network/DartCodeManager.kt +++ b/src/main/kotlin/network/DartCodeManager.kt @@ -3,6 +3,7 @@ package network import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* +import model.KisSession import model.RankingStock import service.AutoTradingManager import java.io.ByteArrayInputStream @@ -19,7 +20,7 @@ data class CorpInfo( ) object DartCodeManager { private val corpCodeMap = mutableMapOf() - private const val DART_API_KEY = "61143d2af0759f6c28ce372d9e339d1e01687abc" // 지범님의 API 키 입력 + private var DART_API_KEY = KisSession.config.dAppKey // 지범님의 API 키 입력 private fun saveXmlDebugFile(xmlBytes: ByteArray) { try { diff --git a/src/main/kotlin/network/NewsService.kt b/src/main/kotlin/network/NewsService.kt index b228317..e44e971 100644 --- a/src/main/kotlin/network/NewsService.kt +++ b/src/main/kotlin/network/NewsService.kt @@ -18,6 +18,7 @@ import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import model.DartFinancialResponse +import model.KisSession import model.NaverNewsResponse import service.DynamicNewsScraper import service.SafeScraper @@ -37,8 +38,8 @@ object NewsService { } suspend fun fetchAndIngestNews(corpInfo: CorpInfo) { - val clientId = "CqXQXHO3h0kqtYsXkePY" // 설정에서 가져오도록 수정 필요 - val clientSecret = "DODCxb1M4Z" + val clientId = KisSession.config.nAppKey // 설정에서 가져오도록 수정 필요 + val clientSecret = KisSession.config.nSecretKey val qlistNews = listOf( "${corpInfo.stockName} 주가", "${corpInfo.stockName} 실적", @@ -83,7 +84,7 @@ object NewsService { suspend fun fetchFinancialGrowth(corpCode: String?): String { if (corpCode != null) { - val apiKey = "61143d2af0759f6c28ce372d9e339d1e01687abc" + val apiKey = KisSession.config.dAppKey // 단일회사 주요계정 API (재무상태표, 손익계산서 주요 항목) val url = "https://opendart.fss.or.kr/api/fnlttSinglAcnt.json?crtfc_key=$apiKey&corp_code=$corpCode&bsns_year=2024&reprt_code=11011" diff --git a/src/main/kotlin/ui/SettingsScreen.kt b/src/main/kotlin/ui/SettingsScreen.kt index 8445e46..bf3b6ae 100644 --- a/src/main/kotlin/ui/SettingsScreen.kt +++ b/src/main/kotlin/ui/SettingsScreen.kt @@ -16,9 +16,19 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json import model.AppConfig import model.KisSession +import network.DartCodeManager import network.KisAuthService import network.KisTradeService import org.jetbrains.exposed.sql.deleteAll @@ -83,6 +93,10 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) { Divider(Modifier.padding(vertical = 16.dp)) + OutlinedTextField(value = config.nAppKey, onValueChange = { config = config.copy(nAppKey = it,) }, label = { Text("NAVER Client ID") }, modifier = Modifier.fillMaxWidth()) + OutlinedTextField(value = config.nSecretKey, onValueChange = { config = config.copy(nSecretKey = it,) }, label = { Text("NAVER Client Secret") }, modifier = Modifier.fillMaxWidth(), visualTransformation = PasswordVisualTransformation()) + OutlinedTextField(value = config.dAppKey, onValueChange = { config = config.copy(dAppKey = it,) }, label = { Text("Dart ApiKey") }, modifier = Modifier.fillMaxWidth()) + // AI 모델 경로 및 드래그 앤 드롭 Text("AI 모델 설정", fontWeight = FontWeight.Bold) Box( @@ -122,6 +136,19 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) { // 1. KisSession.config 업데이트 및 DB 저장 KisSession.config = config DatabaseFactory.saveConfig(config) + DartCodeManager.updateCorpCodes(HttpClient(CIO) { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + encodeDefaults = true // 기본값이 포함된 요청 바디를 정확히 전송하기 위해 필요 + }) + } + // [수정] 모든 로그(Headers + Body)를 찍도록 설정 + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.BODY + } + }) val authService = KisAuthService val tradeService = KisTradeService val authSuccess = authService.refreshAllTokens()