Skip to content

Commit 106f74c

Browse files
committed
feat(be): yml, gradle 수정 및 tool 연계 위한 client, service 수정 (#49)
1 parent d9a25d7 commit 106f74c

File tree

7 files changed

+290
-61
lines changed

7 files changed

+290
-61
lines changed

build.gradle.kts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,6 @@ buildConfig {
128128
"${parts[0].trim()}: ${parts[1].trim().replace("\"", "")}"
129129
}
130130

131-
val sigunguCodes =
132-
file("src/main/resources/sigungu-codes.yml")
133-
.readText()
134-
.substringAfter("codes:")
135-
.lines()
136-
.filter { it.contains(":") }
137-
.joinToString(", ") { line ->
138-
val parts = line.split(":")
139-
"${parts[0].trim()}: ${parts[1].trim().replace("\"", "")}"
140-
}
141-
142131
val contentTypeCodes =
143132
file("src/main/resources/content-type-id.yml")
144133
.readText()
@@ -174,7 +163,6 @@ buildConfig {
174163
.substringBefore("\"")
175164

176165
buildConfigField("String", "AREA_CODES_DESCRIPTION", "\"\"\"$areaCodes\"\"\"")
177-
buildConfigField("String", "SIGUNGU_CODES_DESCRIPTION", "\"\"\"$sigunguCodes\"\"\"")
178166
buildConfigField("String", "CONTENT_TYPE_CODES_DESCRIPTION", "\"\"\"$contentTypeCodes\"\"\"")
179167
buildConfigField("String", "REGION_CODES_DESCRIPTION", "\"\"\"$regionCodes\"\"\"")
180168
buildConfigField("String", "KOREA_TRAVEL_GUIDE_SYSTEM", "\"\"\"$systemPrompt\"\"\"")
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.back.koreaTravelGuide.domain.ai.aiChat.tool
2+
3+
import com.back.backend.BuildConfig
4+
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourDetailParams
5+
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourLocationBasedParams
6+
import com.back.koreaTravelGuide.domain.ai.tour.service.TourService
7+
import org.springframework.ai.tool.annotation.Tool
8+
import org.springframework.ai.tool.annotation.ToolParam
9+
import org.springframework.stereotype.Component
10+
11+
@Component
12+
class TourToolExample(
13+
private val tourService: TourService,
14+
) {
15+
/**
16+
* fetchTours - 지역기반 관광정보 조회
17+
* 케이스 : 부산광역시 사하구에 있는 관광지 조회
18+
* "areacode": "6" 부산
19+
* "sigungucode": "10" 사하구
20+
* "contenttypeid": "12" 관광지
21+
*/
22+
23+
@Tool(description = "areaBasedList2 : 지역기반 관광정보 조회, 특정 지역의 관광 정보 조회")
24+
fun getTourInfo(
25+
@ToolParam(description = BuildConfig.CONTENT_TYPE_CODES_DESCRIPTION, required = true)
26+
contentTypeId: String,
27+
@ToolParam(description = BuildConfig.AREA_CODES_DESCRIPTION, required = true)
28+
areaAndSigunguCode: String,
29+
): String {
30+
// areaAndSigunguCode를 areaCode와 sigunguCode로 분리
31+
val tourParams = tourService.parseParams(contentTypeId, areaAndSigunguCode)
32+
33+
val tourInfo = tourService.fetchTours(tourParams)
34+
35+
return tourInfo.toString() ?: "지역기반 관광정보 조회를 가져올 수 없습니다."
36+
}
37+
38+
/**
39+
* fetchLocationBasedTours - 위치기반 관광정보 조회
40+
* 케이스 : 서울특별시 중구 명동 근처 100m 이내에있는 음식점 조회
41+
* "areacode": "1" 서울
42+
* "sigungucode": "24" 중구
43+
* "contenttypeid": "39" 음식점
44+
* "mapx": "126.98375",
45+
* "mapy": "37.563446",
46+
* "radius": "100",
47+
*/
48+
49+
@Tool(description = "locationBasedList2 : 위치기반 관광정보 조회, 특정 위치 기반의 관광 정보 조회")
50+
fun get(
51+
@ToolParam(description = BuildConfig.CONTENT_TYPE_CODES_DESCRIPTION, required = true)
52+
contentTypeId: String,
53+
@ToolParam(description = BuildConfig.AREA_CODES_DESCRIPTION, required = true)
54+
areaAndSigunguCode: String,
55+
@ToolParam(description = "WGS84 경도", required = true)
56+
mapX: String = "126.98375",
57+
@ToolParam(description = "WGS84 위도", required = true)
58+
mapY: String = "37.563446",
59+
@ToolParam(description = "검색 반경(m)", required = true)
60+
radius: String = "100",
61+
): String {
62+
// areaAndSigunguCode를 areaCode와 sigunguCode로 분리
63+
val tourParams = tourService.parseParams(contentTypeId, areaAndSigunguCode)
64+
val locationBasedParams = TourLocationBasedParams(mapX, mapY, radius)
65+
66+
val tourLocationBasedInfo = tourService.fetchLocationBasedTours(tourParams, locationBasedParams)
67+
68+
return tourLocationBasedInfo.toString() ?: "위치기반 관광정보 조회를 가져올 수 없습니다."
69+
}
70+
71+
/**
72+
* fetchTourDetail - 상세조회
73+
* 케이스 : 콘텐츠ID가 “126128”인 관광정보의 “상베 정보” 조회
74+
* "contentid": "127974",
75+
*/
76+
77+
@Tool(description = "detailCommon2 : 관광정보 상세조회, 특정 관광 정보의 상세 정보 조회")
78+
fun get(
79+
@ToolParam(description = "Tour API Item에 각각 할당된 contentId", required = true)
80+
contentId: String = "127974",
81+
): String {
82+
val tourDetailParams = TourDetailParams(contentId)
83+
84+
val tourDetailInfo = tourService.fetchTourDetail(tourDetailParams)
85+
86+
return tourDetailInfo.toString() ?: "관광정보 상세조회를 가져올 수 없습니다."
87+
}
88+
}

src/main/kotlin/com/back/koreaTravelGuide/domain/ai/tour/client/TourApiClient.kt

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package com.back.koreaTravelGuide.domain.ai.tour.client
22

3-
import com.back.koreaTravelGuide.domain.ai.tour.dto.LocationBasedParams
3+
import com.back.koreaTravelGuide.common.logging.log
44
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourDetailItem
55
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourDetailParams
66
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourDetailResponse
77
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourItem
8+
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourLocationBasedParams
89
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourParams
910
import com.back.koreaTravelGuide.domain.ai.tour.dto.TourResponse
1011
import com.fasterxml.jackson.databind.JsonNode
1112
import com.fasterxml.jackson.databind.ObjectMapper
12-
import org.slf4j.LoggerFactory
1313
import org.springframework.beans.factory.annotation.Value
1414
import org.springframework.stereotype.Component
1515
import org.springframework.web.client.RestTemplate
16+
import org.springframework.web.reactive.function.server.RequestPredicates.queryParam
1617
import org.springframework.web.util.UriComponentsBuilder
1718
import java.net.URI
1819

@@ -24,9 +25,6 @@ class TourApiClient(
2425
@Value("\${tour.api.key}") private val serviceKey: String,
2526
@Value("\${tour.api.base-url}") private val apiUrl: String,
2627
) {
27-
// println 대신 SLF4J 로거 사용
28-
private val logger = LoggerFactory.getLogger(TourApiClient::class.java)
29-
3028
// 요청 URL 구성
3129
private fun buildUrl(params: TourParams): URI =
3230
UriComponentsBuilder.fromUri(URI.create(apiUrl))
@@ -44,14 +42,11 @@ class TourApiClient(
4442

4543
// 지역 기반 관광 정보 조회 (areaBasedList2)
4644
fun fetchTourInfo(params: TourParams): TourResponse {
47-
logger.info("지역 기반 관광 정보 조회 시작")
48-
4945
val url = buildUrl(params)
50-
logger.info("Tour API URL 생성 : $url")
5146

5247
val body =
5348
runCatching { restTemplate.getForObject(url, String::class.java) }
54-
.onFailure { logger.error("관광 정보 조회 실패", it) }
49+
.onFailure { log.error("관광 정보 조회 실패", it) }
5550
.getOrNull()
5651

5752
return body
@@ -61,27 +56,30 @@ class TourApiClient(
6156
}
6257

6358
// 위치기반 관광정보 조회 (locationBasedList2)
64-
fun fetchLocationBasedTours(params: LocationBasedParams): TourResponse {
59+
fun fetchLocationBasedTours(
60+
tourParams: TourParams,
61+
locationParams: TourLocationBasedParams,
62+
): TourResponse {
6563
val url =
6664
UriComponentsBuilder.fromUri(URI.create(apiUrl))
6765
.path("/locationBasedList2")
6866
.queryParam("serviceKey", serviceKey)
6967
.queryParam("MobileOS", "WEB")
7068
.queryParam("MobileApp", "KoreaTravelGuide")
7169
.queryParam("_type", "json")
72-
.queryParam("mapX", params.mapX)
73-
.queryParam("mapY", params.mapY)
74-
.queryParam("radius", params.radius)
75-
.queryParam("contentTypeId", params.contentTypeId)
76-
.queryParam("areaCode", params.areaCode)
77-
.queryParam("sigunguCode", params.sigunguCode)
70+
.queryParam("mapX", locationParams.mapX)
71+
.queryParam("mapY", locationParams.mapY)
72+
.queryParam("radius", locationParams.radius)
73+
.queryParam("contentTypeId", tourParams.contentTypeId)
74+
.queryParam("areaCode", tourParams.areaCode)
75+
.queryParam("sigunguCode", tourParams.sigunguCode)
7876
.build()
7977
.encode()
8078
.toUri()
8179

8280
val body =
8381
runCatching { restTemplate.getForObject(url, String::class.java) }
84-
.onFailure { logger.error("위치기반 관광 정보 조회 실패", it) }
82+
.onFailure { log.error("위치기반 관광 정보 조회 실패", it) }
8583
.getOrNull()
8684

8785
return body
@@ -91,7 +89,7 @@ class TourApiClient(
9189
}
9290

9391
// 공통정보 조회 (detailCommon2)
94-
fun fetchTourCommonDetail(params: TourDetailParams): TourDetailResponse {
92+
fun fetchTourDetail(params: TourDetailParams): TourDetailResponse {
9593
val url =
9694
UriComponentsBuilder.fromUri(URI.create(apiUrl))
9795
.path("/detailCommon2")
@@ -106,7 +104,7 @@ class TourApiClient(
106104

107105
val body =
108106
runCatching { restTemplate.getForObject(url, String::class.java) }
109-
.onFailure { logger.error("공통정보 조회 실패", it) }
107+
.onFailure { log.error("공통정보 조회 실패", it) }
110108
.getOrNull()
111109

112110
return body
@@ -179,7 +177,7 @@ class TourApiClient(
179177
.asText()
180178

181179
if (resultCode != "0000") {
182-
logger.warn("{} API resultCode={}", apiName, resultCode)
180+
log.warn("{} API resultCode={}", apiName, resultCode)
183181
return emptyList()
184182
}
185183

src/main/kotlin/com/back/koreaTravelGuide/domain/ai/tour/dto/LocationBasedParams.kt renamed to src/main/kotlin/com/back/koreaTravelGuide/domain/ai/tour/dto/TourLocationBasedParams.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ package com.back.koreaTravelGuide.domain.ai.tour.dto
55
* 위치기반 관광정보 조회 요청 파라미터 (locationBasedList2)
66
* 필수 좌표 값(mapX, mapY, radius)은 NonNull로 정의해 호출 시점에 무조건 전달되도록 보장한다.
77
*/
8-
data class LocationBasedParams(
9-
val mapX: Double,
10-
val mapY: Double,
11-
val radius: Int,
12-
val contentTypeId: String? = null,
13-
val areaCode: String? = null,
14-
val sigunguCode: String? = null,
8+
data class TourLocationBasedParams(
9+
val mapX: String,
10+
val mapY: String,
11+
val radius: String,
1512
)

0 commit comments

Comments
 (0)