Auto-fill booking city via pin geocoding
All checks were successful
build-and-deploy / build-deploy (push) Successful in 33s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 33s
This commit is contained in:
@@ -2,6 +2,7 @@ package com.android.trisolarisserver.component
|
||||
|
||||
import com.android.trisolarisserver.controller.DocumentPrompts
|
||||
import com.android.trisolarisserver.db.repo.GuestRepo
|
||||
import com.android.trisolarisserver.db.repo.BookingRepo
|
||||
import com.android.trisolarisserver.models.booking.GuestDocument
|
||||
import com.android.trisolarisserver.models.booking.GuestVehicle
|
||||
import com.android.trisolarisserver.repo.GuestVehicleRepo
|
||||
@@ -16,7 +17,9 @@ class DocumentExtractionService(
|
||||
private val guestRepo: GuestRepo,
|
||||
private val guestVehicleRepo: GuestVehicleRepo,
|
||||
private val propertyRepo: PropertyRepo,
|
||||
private val paddleOcrClient: PaddleOcrClient
|
||||
private val paddleOcrClient: PaddleOcrClient,
|
||||
private val bookingRepo: BookingRepo,
|
||||
private val googleGeocodingClient: GoogleGeocodingClient
|
||||
) {
|
||||
private val logger = LoggerFactory.getLogger(DocumentExtractionService::class.java)
|
||||
|
||||
@@ -241,6 +244,7 @@ class DocumentExtractionService(
|
||||
normalizePinCode(results)
|
||||
normalizeIdNumber(results)
|
||||
markAadhaarIfValid(results)
|
||||
applyBookingCityUpdates(document, results)
|
||||
results["docType"] = computeDocType(results, handled)
|
||||
applyGuestUpdates(document, propertyId, results)
|
||||
return ExtractionResult(results, handled)
|
||||
@@ -421,6 +425,27 @@ class DocumentExtractionService(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyBookingCityUpdates(document: GuestDocument, results: Map<String, String>) {
|
||||
val booking = document.booking
|
||||
if (booking.fromCity?.isNotBlank() == true && booking.toCity?.isNotBlank() == true) return
|
||||
val pin = cleanedValue(results[DocumentPrompts.PIN_CODE.first]) ?: return
|
||||
if (!isValidPin(pin)) return
|
||||
val resolved = googleGeocodingClient.resolveCityState(pin) ?: return
|
||||
var updated = false
|
||||
if (booking.fromCity.isNullOrBlank()) {
|
||||
booking.fromCity = resolved
|
||||
updated = true
|
||||
}
|
||||
if (booking.toCity.isNullOrBlank()) {
|
||||
booking.toCity = resolved
|
||||
updated = true
|
||||
}
|
||||
if (updated) {
|
||||
booking.updatedAt = OffsetDateTime.now()
|
||||
bookingRepo.save(booking)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ExtractionResult(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.android.trisolarisserver.component
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import org.springframework.web.util.UriComponentsBuilder
|
||||
|
||||
@Component
|
||||
class GoogleGeocodingClient(
|
||||
private val restTemplate: RestTemplate,
|
||||
private val objectMapper: ObjectMapper,
|
||||
@Value("\${google.maps.apiKey:}")
|
||||
private val apiKey: String,
|
||||
@Value("\${google.maps.geocode.baseUrl:https://maps.googleapis.com/maps/api/geocode/json}")
|
||||
private val baseUrl: String
|
||||
) {
|
||||
private val logger = LoggerFactory.getLogger(GoogleGeocodingClient::class.java)
|
||||
|
||||
fun resolveCityState(pinCode: String): String? {
|
||||
if (apiKey.isBlank()) return null
|
||||
return try {
|
||||
val url = UriComponentsBuilder.fromUriString(baseUrl)
|
||||
.queryParam("address", "${pinCode} India")
|
||||
.queryParam("key", apiKey)
|
||||
.toUriString()
|
||||
val response = restTemplate.getForEntity(url, String::class.java)
|
||||
val body = response.body ?: return null
|
||||
parseCityState(body)
|
||||
} catch (ex: Exception) {
|
||||
logger.warn("Geocoding failed: {}", ex.message)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseCityState(body: String): String? {
|
||||
val root = objectMapper.readTree(body)
|
||||
val results = root.path("results")
|
||||
if (!results.isArray || results.isEmpty) return null
|
||||
val components = results.first().path("address_components")
|
||||
if (!components.isArray) return null
|
||||
|
||||
var city: String? = null
|
||||
var state: String? = null
|
||||
for (comp in components) {
|
||||
val types = comp.path("types").mapNotNull { it.asText(null) }.toSet()
|
||||
when {
|
||||
"locality" in types -> city = comp.path("long_name").asText(null) ?: city
|
||||
"administrative_area_level_2" in types -> if (city == null) {
|
||||
city = comp.path("long_name").asText(null)
|
||||
}
|
||||
"administrative_area_level_1" in types -> state = comp.path("long_name").asText(null) ?: state
|
||||
}
|
||||
}
|
||||
if (city.isNullOrBlank() && state.isNullOrBlank()) return null
|
||||
return listOfNotNull(city?.trim()?.ifBlank { null }, state?.trim()?.ifBlank { null }).joinToString(", ")
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,4 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/trisolaris
|
||||
ai.llama.baseUrl=http://localhost:8089/v1/chat/completions
|
||||
logging.level.com.android.trisolarisserver.controller.Auth=INFO
|
||||
storage.documents.aiBaseUrl=http://127.0.0.1:18921
|
||||
ocr.paddle.baseUrl=http://127.0.0.1:9001/ocr
|
||||
ocr.paddle.baseUrl=http://127.0.0.1:9001/ocr
|
||||
|
||||
@@ -33,3 +33,5 @@ ocr.paddle.baseUrl=https://ocr.hoteltrisolaris.in/
|
||||
ocr.paddle.minScore=0.9
|
||||
ocr.paddle.minAverageScore=0.75
|
||||
ocr.paddle.minTextLength=4
|
||||
google.maps.apiKey=AIzaSyAMuRNFWjccKSmPeR0loQI8etHMDtUIZ_k
|
||||
google.maps.geocode.baseUrl=https://maps.googleapis.com/maps/api/geocode/json
|
||||
|
||||
Reference in New Issue
Block a user