Remove OpenAI fallback
All checks were successful
build-and-deploy / build-deploy (push) Successful in 32s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 32s
This commit is contained in:
@@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory
|
||||
@org.springframework.stereotype.Component
|
||||
class DocumentExtractionService(
|
||||
private val llamaClient: LlamaClient,
|
||||
private val openAIVisionClient: OpenAIVisionClient,
|
||||
private val guestRepo: GuestRepo,
|
||||
private val guestVehicleRepo: GuestVehicleRepo,
|
||||
private val propertyRepo: PropertyRepo
|
||||
@@ -297,20 +296,8 @@ class DocumentExtractionService(
|
||||
return
|
||||
}
|
||||
|
||||
logger.info("Aadhaar retry failed; using OpenAI fallback")
|
||||
val fallback = openAIVisionClient.extractAadhaarNumber(
|
||||
publicImageUrl,
|
||||
document.storagePath,
|
||||
document.contentType
|
||||
) ?: ""
|
||||
val fallbackNormalized = normalizeDigits(cleanedValue(fallback))
|
||||
if (fallbackNormalized != null && isValidAadhaar(fallbackNormalized)) {
|
||||
results[key] = formatAadhaar(fallbackNormalized)
|
||||
} else {
|
||||
val len = fallbackNormalized?.length ?: 0
|
||||
logger.warn("OpenAI fallback failed to produce valid Aadhaar (digits={})", len)
|
||||
results[key] = "NONE"
|
||||
}
|
||||
logger.warn("Aadhaar retry failed; setting idNumber=NONE")
|
||||
results[key] = "NONE"
|
||||
}
|
||||
|
||||
private fun applyGuestUpdates(
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
package com.android.trisolarisserver.component
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.http.HttpEntity
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import org.springframework.web.client.HttpStatusCodeException
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@Component
|
||||
class OpenAIVisionClient(
|
||||
private val restTemplate: RestTemplate,
|
||||
private val objectMapper: ObjectMapper,
|
||||
@Value("\${openai.apiKey:}")
|
||||
private val apiKey: String,
|
||||
@Value("\${openai.baseUrl:https://api.openai.com/v1/responses}")
|
||||
private val baseUrl: String,
|
||||
@Value("\${openai.model:gpt-5-mini}")
|
||||
private val model: String
|
||||
) {
|
||||
private val logger = LoggerFactory.getLogger(OpenAIVisionClient::class.java)
|
||||
|
||||
fun extractAadhaarNumber(imageUrl: String, localPath: String?, contentType: String?): String? {
|
||||
if (apiKey.isBlank()) {
|
||||
logger.warn("OpenAI fallback skipped: openai.apiKey is blank")
|
||||
return null
|
||||
}
|
||||
|
||||
val headers = HttpHeaders()
|
||||
headers.contentType = MediaType.APPLICATION_JSON
|
||||
headers.setBearerAuth(apiKey)
|
||||
val resolvedImage = buildDataUrl(localPath, contentType) ?: imageUrl
|
||||
val first = call(
|
||||
resolvedImage,
|
||||
"Read extremely carefully. Aadhaar number = 12 digits. Reply ONLY the 12 digits or NONE.",
|
||||
"aadhaar_default",
|
||||
headers
|
||||
)
|
||||
if (!first.isNullOrBlank() && !first.equals("NONE", ignoreCase = true)) {
|
||||
return first
|
||||
}
|
||||
if (first != null) {
|
||||
logger.info("OpenAI fallback returned NONE; retrying with focused prompt")
|
||||
}
|
||||
return call(
|
||||
resolvedImage,
|
||||
"Focus on the 12-digit Aadhaar number printed on the card (often vertical on the left). Reply ONLY the 12 digits or NONE.",
|
||||
"aadhaar_left_strip",
|
||||
headers
|
||||
)
|
||||
}
|
||||
|
||||
private fun call(imageUrl: String, prompt: String, promptId: String, headers: HttpHeaders): String? {
|
||||
val payload = mapOf(
|
||||
"model" to model,
|
||||
"instructions" to "Read extremely carefully. Reply ONLY the 12 digits or NONE. No extra text.",
|
||||
"temperature" to 0.0,
|
||||
"top_p" to 1.0,
|
||||
"max_output_tokens" to 16,
|
||||
"input" to listOf(
|
||||
mapOf(
|
||||
"role" to "user",
|
||||
"content" to listOf(
|
||||
mapOf(
|
||||
"type" to "input_text",
|
||||
"text" to prompt
|
||||
),
|
||||
mapOf(
|
||||
"type" to "input_image",
|
||||
"image_url" to imageUrl,
|
||||
"detail" to "high"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
val entity = HttpEntity(payload, headers)
|
||||
return try {
|
||||
logger.info("OpenAI fallback request model={} url={}", model, baseUrl)
|
||||
val response = restTemplate.postForEntity(baseUrl, entity, String::class.java)
|
||||
val body = response.body ?: return null
|
||||
val node = objectMapper.readTree(body)
|
||||
|
||||
val outputText = node.path("output_text").asText()
|
||||
if (outputText.isNotBlank()) {
|
||||
logger.info(
|
||||
"OpenAI fallback output_text prompt={} result={}",
|
||||
promptId,
|
||||
summarizeOutput(outputText)
|
||||
)
|
||||
return outputText
|
||||
}
|
||||
|
||||
val outputArray = node.path("output")
|
||||
if (outputArray.isArray && outputArray.size() > 0) {
|
||||
val content = outputArray[0].path("content")
|
||||
if (content.isArray && content.size() > 0) {
|
||||
val text = content[0].path("text").asText()
|
||||
if (text.isNotBlank()) {
|
||||
logger.info(
|
||||
"OpenAI fallback content text prompt={} result={}",
|
||||
promptId,
|
||||
summarizeOutput(text)
|
||||
)
|
||||
return text
|
||||
}
|
||||
}
|
||||
}
|
||||
val errorNode = node.path("error")
|
||||
if (!errorNode.isMissingNode) {
|
||||
val code = errorNode.path("code").asText()
|
||||
val type = errorNode.path("type").asText()
|
||||
logger.warn("OpenAI fallback error code={} type={}", code, type)
|
||||
}
|
||||
null
|
||||
} catch (e: HttpStatusCodeException) {
|
||||
logger.warn("OpenAI fallback HTTP error status={} body={}", e.statusCode.value(), e.responseBodyAsString.take(200))
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
logger.warn("OpenAI fallback failed: {}", e.message)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun summarizeOutput(value: String): String {
|
||||
val trimmed = value.trim()
|
||||
if (trimmed.equals("NONE", ignoreCase = true)) return "NONE"
|
||||
val digits = trimmed.filter { it.isDigit() }
|
||||
return if (digits.isNotBlank()) "digits_len=${digits.length}" else "text_len=${trimmed.length}"
|
||||
}
|
||||
|
||||
private fun buildDataUrl(localPath: String?, contentType: String?): String? {
|
||||
if (localPath.isNullOrBlank()) return null
|
||||
val type = contentType ?: guessContentType(localPath) ?: return null
|
||||
return try {
|
||||
val bytes = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(localPath))
|
||||
val base64 = java.util.Base64.getEncoder().encodeToString(bytes)
|
||||
"data:$type;base64,$base64"
|
||||
} catch (e: Exception) {
|
||||
logger.warn("OpenAI fallback failed to read local image: {}", e.message)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun guessContentType(path: String): String? {
|
||||
return when {
|
||||
path.endsWith(".jpg", true) || path.endsWith(".jpeg", true) -> "image/jpeg"
|
||||
path.endsWith(".png", true) -> "image/png"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,3 @@ ai.llama.topP=0.8
|
||||
ai.llama.minP=0.2
|
||||
ai.llama.repeatPenalty=1.0
|
||||
ai.llama.topK=40
|
||||
openai.apiKey=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
|
||||
openai.baseUrl=https://api.openai.com/v1/responses
|
||||
openai.model=gpt-5.1
|
||||
|
||||
Reference in New Issue
Block a user