Refactorizacion de logica de analisis de las preguntas con la IA y que acepte y respete las reglas de imagenes
This commit is contained in:
@@ -3343,7 +3343,14 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
}
|
||||
|
||||
const handlePhotoChange = async (questionId, files) => {
|
||||
const filesArray = Array.from(files)
|
||||
const question = questions.find(q => q.id === questionId)
|
||||
let filesArray = Array.from(files)
|
||||
|
||||
// Validar límite de fotos
|
||||
if (question.max_photos && filesArray.length > question.max_photos) {
|
||||
alert(`⚠️ Solo puedes subir hasta ${question.max_photos} foto${question.max_photos > 1 ? 's' : ''} para esta pregunta`)
|
||||
filesArray = filesArray.slice(0, question.max_photos)
|
||||
}
|
||||
|
||||
// Update photos immediately
|
||||
setAnswers(prev => ({
|
||||
@@ -3381,9 +3388,12 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
console.log(`📝 Usando prompt personalizado: ${question.ai_prompt.substring(0, 50)}...`)
|
||||
}
|
||||
|
||||
// Analyze each photo
|
||||
// Analyze each photo sequentially
|
||||
const analyses = []
|
||||
for (const file of files) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
console.log(`📸 Analizando foto ${i + 1} de ${files.length}: ${file.name}`)
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('question_id', question.id.toString())
|
||||
@@ -3392,6 +3402,7 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
console.log(' - question_id:', question.id)
|
||||
console.log(' - question.text:', question.text)
|
||||
console.log(' - question.ai_prompt:', question.ai_prompt || 'NO TIENE')
|
||||
console.log(' - imagen:', i + 1, 'de', files.length)
|
||||
|
||||
// Include inspection_id for vehicle context
|
||||
if (inspectionId) {
|
||||
@@ -3424,8 +3435,8 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
|
||||
// Check if AI analysis was successful
|
||||
if (result.success && result.analysis) {
|
||||
analyses.push(result)
|
||||
console.log('✅ Análisis IA exitoso')
|
||||
analyses.push({ ...result, imageIndex: i + 1, fileName: file.name })
|
||||
console.log('✅ Análisis IA exitoso para imagen', i + 1)
|
||||
console.log(' - Provider:', result.provider)
|
||||
console.log(' - Model:', result.model)
|
||||
console.log(' - Status:', result.analysis.status)
|
||||
@@ -3435,6 +3446,7 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
// Show user-friendly error
|
||||
if (result.error && result.error.includes('No AI configuration')) {
|
||||
alert('⚙️ Por favor configura tu API key en Configuración primero.')
|
||||
break // Stop analyzing if no API key
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -3445,65 +3457,90 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
|
||||
if (analyses.length > 0) {
|
||||
console.log('✅ Análisis recibidos:', analyses.length)
|
||||
// Process analysis results
|
||||
const firstResult = analyses[0]
|
||||
const analysis = firstResult.analysis
|
||||
console.log('📊 Análisis completo:', analysis)
|
||||
|
||||
let suggestedAnswer = null
|
||||
let observationsText = ''
|
||||
let worstStatus = 'ok' // Track the worst status across all images
|
||||
|
||||
// Check if analysis is an object (structured JSON response)
|
||||
if (typeof analysis === 'object' && analysis !== null) {
|
||||
// Extract structured information
|
||||
const status = analysis.status || 'ok'
|
||||
const observations = analysis.observations || ''
|
||||
const recommendation = analysis.recommendation || ''
|
||||
const confidence = analysis.confidence || 0.7
|
||||
if (analyses.length === 1) {
|
||||
// Single image analysis
|
||||
const firstResult = analyses[0]
|
||||
const analysis = firstResult.analysis
|
||||
console.log('📊 Análisis de imagen única:', analysis)
|
||||
|
||||
// Build observations text
|
||||
observationsText = `🤖 Análisis IA (${(confidence * 100).toFixed(0)}% confianza):\n${observations}`
|
||||
if (recommendation) {
|
||||
observationsText += `\n\n💡 Recomendación: ${recommendation}`
|
||||
// Check if analysis is an object (structured JSON response)
|
||||
if (typeof analysis === 'object' && analysis !== null) {
|
||||
// Extract structured information
|
||||
const status = analysis.status || 'ok'
|
||||
const observations = analysis.observations || ''
|
||||
const recommendation = analysis.recommendation || ''
|
||||
const confidence = analysis.confidence || 0.7
|
||||
|
||||
// Build observations text
|
||||
observationsText = `🤖 Análisis IA (${(confidence * 100).toFixed(0)}% confianza):\n${observations}`
|
||||
if (recommendation) {
|
||||
observationsText += `\n\n💡 Recomendación: ${recommendation}`
|
||||
}
|
||||
worstStatus = status
|
||||
} else if (typeof analysis === 'string') {
|
||||
observationsText = `🤖 Análisis IA:\n${analysis}`
|
||||
}
|
||||
} else {
|
||||
// Multiple images - summarize all analyses
|
||||
console.log('📊 Resumen de', analyses.length, 'análisis:')
|
||||
observationsText = `🤖 Análisis IA de ${analyses.length} imágenes:\n\n`
|
||||
|
||||
// Map status to answer based on question type
|
||||
if (question.type === 'pass_fail') {
|
||||
if (status === 'ok') {
|
||||
suggestedAnswer = 'pass'
|
||||
} else if (status === 'critical' || status === 'minor') {
|
||||
suggestedAnswer = 'fail'
|
||||
}
|
||||
} else if (question.type === 'good_bad') {
|
||||
if (status === 'ok') {
|
||||
suggestedAnswer = 'good'
|
||||
} else if (status === 'minor') {
|
||||
suggestedAnswer = 'regular'
|
||||
} else if (status === 'critical') {
|
||||
suggestedAnswer = 'bad'
|
||||
const statusPriority = { 'critical': 3, 'minor': 2, 'warning': 2, 'ok': 1 }
|
||||
let maxPriority = 0
|
||||
|
||||
analyses.forEach((result, index) => {
|
||||
const analysis = result.analysis
|
||||
observationsText += `📸 Imagen ${result.imageIndex}:\n`
|
||||
|
||||
if (typeof analysis === 'object' && analysis !== null) {
|
||||
const status = analysis.status || 'ok'
|
||||
const observations = analysis.observations || ''
|
||||
const confidence = analysis.confidence || 0.7
|
||||
|
||||
observationsText += ` Estado: ${status.toUpperCase()}`
|
||||
observationsText += ` (${(confidence * 100).toFixed(0)}% confianza)\n`
|
||||
observationsText += ` ${observations}\n`
|
||||
|
||||
// Track worst status
|
||||
const priority = statusPriority[status] || 1
|
||||
if (priority > maxPriority) {
|
||||
maxPriority = priority
|
||||
worstStatus = status
|
||||
}
|
||||
} else if (typeof analysis === 'string') {
|
||||
observationsText += ` ${analysis}\n`
|
||||
}
|
||||
observationsText += '\n'
|
||||
})
|
||||
|
||||
// Add overall recommendation
|
||||
observationsText += `📋 Resumen General:\n`
|
||||
observationsText += ` Estado más crítico detectado: ${worstStatus.toUpperCase()}\n`
|
||||
}
|
||||
|
||||
// Map worst status to answer
|
||||
if (question.type === 'pass_fail') {
|
||||
if (worstStatus === 'ok') {
|
||||
suggestedAnswer = 'pass'
|
||||
} else if (worstStatus === 'critical' || worstStatus === 'minor') {
|
||||
suggestedAnswer = 'fail'
|
||||
}
|
||||
} else if (typeof analysis === 'string') {
|
||||
// Fallback for plain text responses
|
||||
observationsText = `🤖 Análisis IA:\n${analysis}`
|
||||
const analysisLower = analysis.toLowerCase()
|
||||
|
||||
if (question.type === 'pass_fail') {
|
||||
if (analysisLower.includes('pasa') || analysisLower.includes('correcto') || analysisLower.includes('bueno') || analysisLower.includes('ok')) {
|
||||
suggestedAnswer = 'pass'
|
||||
} else if (analysisLower.includes('falla') || analysisLower.includes('incorrecto') || analysisLower.includes('problema') || analysisLower.includes('critical')) {
|
||||
suggestedAnswer = 'fail'
|
||||
}
|
||||
} else if (question.type === 'good_bad') {
|
||||
if (analysisLower.includes('bueno') || analysisLower.includes('excelente')) {
|
||||
suggestedAnswer = 'good'
|
||||
} else if (analysisLower.includes('regular') || analysisLower.includes('aceptable')) {
|
||||
suggestedAnswer = 'regular'
|
||||
} else if (analysisLower.includes('malo') || analysisLower.includes('deficiente')) {
|
||||
suggestedAnswer = 'bad'
|
||||
}
|
||||
} else if (question.type === 'good_bad') {
|
||||
if (worstStatus === 'ok') {
|
||||
suggestedAnswer = 'good'
|
||||
} else if (worstStatus === 'minor' || worstStatus === 'warning') {
|
||||
suggestedAnswer = 'regular'
|
||||
} else if (worstStatus === 'critical') {
|
||||
suggestedAnswer = 'bad'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// In FULL mode, auto-fill the answer
|
||||
if (checklist.ai_mode === 'full' && suggestedAnswer) {
|
||||
setAnswers(prev => ({
|
||||
@@ -3513,7 +3550,7 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
value: suggestedAnswer,
|
||||
observations: observationsText,
|
||||
photos: files,
|
||||
aiAnalysis: firstResult.analysis // Guardar análisis completo de IA
|
||||
aiAnalysis: analyses // Guardar todos los análisis
|
||||
}
|
||||
}))
|
||||
console.log(`🤖 FULL MODE: Respuesta auto-completada con: ${suggestedAnswer}`)
|
||||
@@ -3883,7 +3920,12 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
{currentQuestion.allow_photos && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Fotografías (opcional)
|
||||
Fotografías *
|
||||
{currentQuestion.max_photos && (
|
||||
<span className="ml-2 text-xs text-gray-600">
|
||||
(máximo {currentQuestion.max_photos} foto{currentQuestion.max_photos > 1 ? 's' : ''})
|
||||
</span>
|
||||
)}
|
||||
{(checklist.ai_mode === 'assisted' || checklist.ai_mode === 'full') && (
|
||||
<span className="ml-2 text-xs text-blue-600">
|
||||
🤖 Análisis IA activado
|
||||
@@ -3893,10 +3935,11 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
multiple={currentQuestion.max_photos > 1}
|
||||
onChange={(e) => handlePhotoChange(currentQuestion.id, e.target.files)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
|
||||
disabled={aiAnalyzing}
|
||||
required
|
||||
/>
|
||||
|
||||
{aiAnalyzing && (
|
||||
@@ -3941,6 +3984,11 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
{currentQuestionIndex < getVisibleQuestions().length - 1 ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
// Validar que se hayan subido fotos si son obligatorias
|
||||
if (currentQuestion.allow_photos && (!answers[currentQuestion.id]?.photos || answers[currentQuestion.id].photos.length === 0)) {
|
||||
alert('⚠️ Debes subir al menos una fotografía para esta pregunta')
|
||||
return
|
||||
}
|
||||
saveAnswer(currentQuestion.id)
|
||||
goToQuestion(currentQuestionIndex + 1)
|
||||
}}
|
||||
@@ -3951,6 +3999,11 @@ function InspectionModal({ checklist, user, onClose, onComplete }) {
|
||||
) : (
|
||||
<button
|
||||
onClick={() => {
|
||||
// Validar que se hayan subido fotos si son obligatorias
|
||||
if (currentQuestion.allow_photos && (!answers[currentQuestion.id]?.photos || answers[currentQuestion.id].photos.length === 0)) {
|
||||
alert('⚠️ Debes subir al menos una fotografía para esta pregunta')
|
||||
return
|
||||
}
|
||||
saveAnswer(currentQuestion.id)
|
||||
proceedToSignatures()
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user