Cambios realizados v1.2.11 (Backend) + v1.3.8 (Frontend):

Backend v1.2.11:
Nueva Funcionalidad - Control de Generación de PDF:
Campo nuevo: generate_pdf en modelo Checklist (Boolean, default: True)
Lógica modificada: Al completar inspección se verifica si el checklist tiene habilitada la generación de PDF
Comportamiento:
Si generate_pdf = True → Se genera y guarda el PDF automáticamente
Si generate_pdf = False → No se genera PDF, pdf_url queda en NULL
Logs informativos: Muestra en consola si el PDF se generó o se omitió
Frontend v1.3.8:
Interfaz para Control de PDF:
Checkbox nuevo en modal de edición de checklist: "Generar PDF automáticamente al completar inspección"
Estado por defecto: Activado (mantiene comportamiento actual)
Persistencia: El valor se guarda en la base de datos al editar checklist
Dónde está:
Admin → Checklists → Click en "✏️ Editar" de cualquier checklist
Debajo del checkbox de "Habilitar sistema de puntuación"
This commit is contained in:
2025-12-08 09:44:33 -03:00
parent 7fd37d0992
commit 0c0812efe9
8 changed files with 175 additions and 46 deletions

View File

@@ -278,7 +278,7 @@ def extract_pdf_text_smart(pdf_content: bytes, max_chars: int = None) -> dict:
}
BACKEND_VERSION = "1.2.9"
BACKEND_VERSION = "1.2.11"
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
# S3/MinIO configuration
@@ -2049,54 +2049,30 @@ def generate_inspection_pdf(inspection_id: int, db: Session) -> str:
# ===== LÓGICA ESPECIAL PARA AI_ASSISTANT =====
if is_ai_assistant and ans.chat_history:
# Generar resumen estructurado del chat
import asyncio
# Mostrar resumen simple SIN generar con IA (para evitar lentitud y peso)
try:
# Ejecutar función async de forma sincrónica
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
chat_summary = loop.run_until_complete(
generate_chat_summary(ans.chat_history, question.text)
)
loop.close()
chat_data = ans.chat_history if isinstance(ans.chat_history, list) else json.loads(ans.chat_history)
total_messages = len(chat_data)
user_messages = sum(1 for m in chat_data if m.get('role') == 'user')
assistant_messages = sum(1 for m in chat_data if m.get('role') == 'assistant')
# Renderizar informe narrativo
question_data.append([
Paragraph(f"<b>💬 INFORME DE DIAGNÓSTICO ASISTIDO</b>",
Paragraph(f"<b>💬 DIAGNÓSTICO ASISTIDO POR IA</b>",
ParagraphStyle('chat_title', parent=answer_style, fontSize=11,
textColor=colors.HexColor('#2563eb'), fontName='Helvetica-Bold'))
])
# Problema identificado
question_data.append([
Paragraph(f"<b>🔍 Problema Identificado:</b><br/>{chat_summary.get('problema_identificado', 'N/A')}",
Paragraph(f"<b>📊 Resumen de Conversación:</b><br/>"
f"• Total de mensajes: {total_messages}<br/>"
f"• Consultas del mecánico: {user_messages}<br/>"
f"• Respuestas del asistente: {assistant_messages}<br/><br/>"
f"<i>Nota: El historial completo está disponible en el sistema para administradores.</i>",
comment_style)
])
# Hallazgos
if chat_summary.get('hallazgos') and len(chat_summary['hallazgos']) > 0:
hallazgos_text = "<br/>".join([f"{h}" for h in chat_summary['hallazgos']])
question_data.append([
Paragraph(f"<b>📋 Hallazgos:</b><br/>{hallazgos_text}", comment_style)
])
# Diagnóstico
question_data.append([
Paragraph(f"<b>🔧 Diagnóstico:</b><br/>{chat_summary.get('diagnostico', 'N/A')}",
comment_style)
])
# Recomendaciones
if chat_summary.get('recomendaciones') and len(chat_summary['recomendaciones']) > 0:
recomendaciones_text = "<br/>".join([f"{r}" for r in chat_summary['recomendaciones']])
question_data.append([
Paragraph(f"<b>✅ Recomendaciones:</b><br/>{recomendaciones_text}",
ParagraphStyle('recommendations', parent=comment_style,
textColor=colors.HexColor('#16a34a')))
])
except Exception as e:
print(f"❌ Error generando resumen de chat en PDF: {e}")
print(f"❌ Error procesando chat en PDF: {e}")
# Fallback: mostrar que hubo conversación
question_data.append([
Table([
@@ -2284,9 +2260,15 @@ def complete_inspection(
inspection.status = "completed"
inspection.completed_at = datetime.utcnow()
# Generar PDF usando función reutilizable
pdf_url = generate_inspection_pdf(inspection_id, db)
inspection.pdf_url = pdf_url
# Generar PDF solo si el checklist lo tiene habilitado
if inspection.checklist.generate_pdf:
pdf_url = generate_inspection_pdf(inspection_id, db)
inspection.pdf_url = pdf_url
print(f"✅ PDF generado para inspección #{inspection_id}")
else:
inspection.pdf_url = None
print(f"⏭️ PDF NO generado (deshabilitado en checklist) para inspección #{inspection_id}")
db.commit()
db.refresh(inspection)

View File

@@ -47,6 +47,7 @@ class Checklist(Base):
scoring_enabled = Column(Boolean, default=True)
max_score = Column(Integer, default=0)
logo_url = Column(String(500))
generate_pdf = Column(Boolean, default=True) # Controla si se genera PDF al completar
is_active = Column(Boolean, default=True)
created_by = Column(Integer, ForeignKey("users.id"))
created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -71,6 +71,7 @@ class ChecklistBase(BaseModel):
ai_mode: str = "off"
scoring_enabled: bool = True
logo_url: Optional[str] = None
generate_pdf: bool = True
class ChecklistCreate(ChecklistBase):
mechanic_ids: Optional[List[int]] = [] # IDs de mecánicos autorizados
@@ -81,12 +82,14 @@ class ChecklistUpdate(BaseModel):
ai_mode: Optional[str] = None
scoring_enabled: Optional[bool] = None
logo_url: Optional[str] = None
generate_pdf: Optional[bool] = None
is_active: Optional[bool] = None
mechanic_ids: Optional[List[int]] = None # IDs de mecánicos autorizados
class Checklist(ChecklistBase):
id: int
max_score: int
generate_pdf: bool
is_active: bool
created_by: int
created_at: datetime