✅ Soporte para PDFs agregado al sistema de análisis con IA
📋 Cambios Implementados Frontend: ✅ Input acepta image/*,application/pdf ✅ Label actualizado: "Fotografías / Documentos PDF *" ✅ Preview diferenciado: PDFs muestran icono 📝 rojo en lugar de imagen ✅ Nombre de archivo PDF visible en el preview ✅ Contador genérico: "archivo(s) cargado(s)" Backend: ✅ Agregado pypdf==4.0.1 a requirements.txt ✅ Detección automática de PDFs por content_type o extensión ✅ Extracción de texto de PDFs usando pypdf.PdfReader ✅ Validación de PDFs vacíos (sin texto extraíble) ✅ Prompts adaptados automáticamente para PDFs ✅ Soporte en OpenAI y Gemini (análisis de texto en lugar de vision) ✅ Límite de 4000 caracteres del PDF para análisis 🎯 Funcionamiento Usuario sube PDF → Sistema detecta tipo de archivo Extrae texto → PyPDF lee todas las páginas Análisis IA → Envía texto al modelo (no usa Vision API) Respuesta → Misma estructura JSON que con imágenes ⚠️ Limitaciones PDFs escaneados sin OCR no funcionarán (requieren texto seleccionable) Máximo 4000 caracteres del PDF enviados al AI 📦 Versiones Frontend: 1.0.91 → 1.0.92 Backend: 1.0.89 → 1.0.90
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "checklist-frontend",
|
||||
"private": true,
|
||||
"version": "1.0.91",
|
||||
"version": "1.0.92",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Service Worker para PWA con detección de actualizaciones
|
||||
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
|
||||
const CACHE_NAME = 'ayutec-v1.0.91';
|
||||
const CACHE_NAME = 'ayutec-v1.0.92';
|
||||
const urlsToCache = [
|
||||
'/',
|
||||
'/index.html'
|
||||
|
||||
@@ -5007,10 +5007,10 @@ function InspectionModal({ checklist, existingInspection, user, onClose, onCompl
|
||||
{currentQuestion.allow_photos && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Fotografías *
|
||||
Fotografías / Documentos *
|
||||
{currentQuestion.max_photos && (
|
||||
<span className="ml-2 text-xs text-gray-600">
|
||||
(máximo {currentQuestion.max_photos} foto{currentQuestion.max_photos > 1 ? 's' : ''})
|
||||
(máximo {currentQuestion.max_photos} archivo{currentQuestion.max_photos > 1 ? 's' : ''})
|
||||
</span>
|
||||
)}
|
||||
{(checklist.ai_mode === 'assisted' || checklist.ai_mode === 'full') && (
|
||||
@@ -5023,7 +5023,7 @@ function InspectionModal({ checklist, existingInspection, user, onClose, onCompl
|
||||
<input
|
||||
key={`photo-input-${currentQuestion.id}`}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
accept="image/*,application/pdf"
|
||||
multiple={currentQuestion.max_photos > 1}
|
||||
onChange={(e) => {
|
||||
handlePhotoChange(currentQuestion.id, e.target.files)
|
||||
@@ -5038,16 +5038,23 @@ function InspectionModal({ checklist, existingInspection, user, onClose, onCompl
|
||||
{answers[currentQuestion.id]?.photos?.length > 0 && (
|
||||
<div className="mt-3 space-y-2">
|
||||
<div className="text-sm font-medium text-gray-700">
|
||||
{answers[currentQuestion.id].photos.length} foto(s) cargada(s):
|
||||
{answers[currentQuestion.id].photos.length} archivo(s) cargado(s):
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{answers[currentQuestion.id].photos.map((photo, index) => (
|
||||
<div key={index} className="relative group">
|
||||
<img
|
||||
src={URL.createObjectURL(photo)}
|
||||
alt={`Foto ${index + 1}`}
|
||||
className="w-full h-24 object-cover rounded-lg border border-gray-300"
|
||||
/>
|
||||
{photo.type === 'application/pdf' ? (
|
||||
<div className="w-full h-24 flex flex-col items-center justify-center bg-red-50 border-2 border-red-300 rounded-lg">
|
||||
<span className="text-3xl">📝</span>
|
||||
<span className="text-xs text-red-700 mt-1">PDF</span>
|
||||
</div>
|
||||
) : (
|
||||
<img
|
||||
src={URL.createObjectURL(photo)}
|
||||
alt={`Foto ${index + 1}`}
|
||||
className="w-full h-24 object-cover rounded-lg border border-gray-300"
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemovePhoto(currentQuestion.id, index)}
|
||||
@@ -5057,7 +5064,7 @@ function InspectionModal({ checklist, existingInspection, user, onClose, onCompl
|
||||
✕
|
||||
</button>
|
||||
<div className="text-xs text-center text-gray-600 mt-1">
|
||||
Foto {index + 1}
|
||||
{photo.type === 'application/pdf' ? photo.name : `Foto ${index + 1}`}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -140,7 +140,7 @@ export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, se
|
||||
{sidebarOpen && (
|
||||
<div className="mb-3 px-2 py-1.5 bg-indigo-900/30 rounded-lg border border-indigo-700/30">
|
||||
<p className="text-xs text-indigo-300 text-center font-medium">
|
||||
Ayutec v1.0.91
|
||||
Ayutec v1.0.92
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user