Actualziacion de analisis de ia con las imagenes y se agrega el campo de cod operario en el front y en el back
This commit is contained in:
@@ -325,6 +325,7 @@ def create_user(
|
||||
username=user.username,
|
||||
email=user.email,
|
||||
full_name=user.full_name,
|
||||
employee_code=user.employee_code,
|
||||
role=user.role,
|
||||
password_hash=hashed_password,
|
||||
is_active=True
|
||||
@@ -374,6 +375,9 @@ def update_user(
|
||||
if user_update.full_name is not None:
|
||||
db_user.full_name = user_update.full_name
|
||||
|
||||
if user_update.employee_code is not None:
|
||||
db_user.employee_code = user_update.employee_code
|
||||
|
||||
# Solo admin puede cambiar roles
|
||||
if user_update.role is not None:
|
||||
if current_user.role != "admin":
|
||||
@@ -1519,9 +1523,9 @@ def delete_ai_configuration(
|
||||
@app.post("/api/analyze-image")
|
||||
async def analyze_image(
|
||||
file: UploadFile = File(...),
|
||||
question_id: int = None,
|
||||
inspection_id: int = None,
|
||||
custom_prompt: str = None,
|
||||
question_id: int = Form(None),
|
||||
inspection_id: int = Form(None),
|
||||
custom_prompt: str = Form(None),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: models.User = Depends(get_current_user)
|
||||
):
|
||||
@@ -1530,6 +1534,15 @@ async def analyze_image(
|
||||
Usa la configuración de IA activa (OpenAI o Gemini)
|
||||
Incluye contexto del vehículo si se proporciona inspection_id
|
||||
"""
|
||||
print("\n" + "="*80)
|
||||
print("🔍 ANALYZE IMAGE - DEBUG")
|
||||
print("="*80)
|
||||
print(f"📥 Parámetros recibidos:")
|
||||
print(f" - file: {file.filename}")
|
||||
print(f" - question_id: {question_id}")
|
||||
print(f" - inspection_id: {inspection_id}")
|
||||
print(f" - custom_prompt (del Form): {custom_prompt[:100] if custom_prompt else 'NO RECIBIDO'}")
|
||||
|
||||
# Obtener configuración de IA activa
|
||||
ai_config = db.query(models.AIConfiguration).filter(
|
||||
models.AIConfiguration.is_active == True
|
||||
@@ -1551,71 +1564,71 @@ async def analyze_image(
|
||||
question_obj = None
|
||||
if question_id:
|
||||
question_obj = db.query(models.Question).filter(models.Question.id == question_id).first()
|
||||
print(f"📋 Pregunta encontrada:")
|
||||
print(f" - ID: {question_obj.id}")
|
||||
print(f" - Texto: {question_obj.text}")
|
||||
print(f" - ai_prompt en DB: {question_obj.ai_prompt[:100] if question_obj.ai_prompt else 'NO TIENE'}")
|
||||
|
||||
# Si no se proporciona custom_prompt en el Form, usar el de la pregunta
|
||||
if not custom_prompt and question_obj and question_obj.ai_prompt:
|
||||
custom_prompt = question_obj.ai_prompt
|
||||
print(f"✅ Usando ai_prompt de la pregunta de la DB")
|
||||
elif custom_prompt:
|
||||
print(f"✅ Usando custom_prompt del Form")
|
||||
else:
|
||||
print(f"⚠️ NO HAY custom_prompt (ni del Form ni de la DB)")
|
||||
|
||||
print(f"📝 Custom prompt FINAL a usar: {custom_prompt[:150] if custom_prompt else 'NINGUNO'}...")
|
||||
|
||||
# Obtener contexto del vehículo si se proporciona inspection_id
|
||||
vehicle_context = ""
|
||||
if inspection_id:
|
||||
inspection = db.query(models.Inspection).filter(models.Inspection.id == inspection_id).first()
|
||||
if inspection:
|
||||
print(f"🚗 Contexto del vehículo agregado: {inspection.vehicle_brand} {inspection.vehicle_model}")
|
||||
vehicle_context = f"""
|
||||
INFORMACIÓN DEL VEHÍCULO INSPECCIONADO:
|
||||
- Marca: {inspection.vehicle_brand}
|
||||
- Modelo: {inspection.vehicle_model}
|
||||
- Año: {inspection.vehicle_year or 'No especificado'}
|
||||
- Placa: {inspection.vehicle_plate}
|
||||
- Kilometraje: {inspection.mileage} km
|
||||
- Kilometraje: {inspection.vehicle_km} km
|
||||
- Cliente: {inspection.client_name}
|
||||
- OR/Orden: {inspection.or_number}
|
||||
"""
|
||||
else:
|
||||
print(f"⚠️ inspection_id {inspection_id} no encontrado en DB")
|
||||
else:
|
||||
print(f"⚠️ NO se proporcionó inspection_id, sin contexto de vehículo")
|
||||
|
||||
try:
|
||||
# Construir prompt dinámico basado en la pregunta específica
|
||||
if question_obj:
|
||||
# Usar prompt personalizado si está disponible
|
||||
if custom_prompt:
|
||||
# Prompt 100% personalizado por el administrador
|
||||
# Prompt personalizado - DIRECTO Y SIMPLE
|
||||
system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular.
|
||||
|
||||
{vehicle_context}
|
||||
|
||||
INSTRUCCIONES ESPECÍFICAS DEL ADMINISTRADOR PARA ESTA PREGUNTA:
|
||||
TAREA ESPECÍFICA:
|
||||
{custom_prompt}
|
||||
|
||||
PREGUNTA A RESPONDER: "{question_obj.text}"
|
||||
Sección: {question_obj.section}
|
||||
|
||||
IMPORTANTE - VALIDACIÓN ESTRICTA:
|
||||
1. Lee CUIDADOSAMENTE las instrucciones específicas del administrador arriba
|
||||
2. Verifica si la imagen proporcionada PERMITE responder lo que se pide
|
||||
3. Si las instrucciones piden verificar algo dinámico (como "si prende", "si funciona", "si enciende"):
|
||||
- Y la imagen es estática (foto), indica en "recommendation" que NO se puede verificar con una foto estática
|
||||
- Sugiere que se necesita una prueba en vivo o un video
|
||||
4. Si la imagen NO corresponde a lo que piden las instrucciones, indica claramente en "recommendation" qué foto necesitan tomar
|
||||
|
||||
VALIDACIÓN DE IMAGEN:
|
||||
- Si piden verificar funcionamiento (prende, enciende, funciona) pero solo hay una foto → Indica "No se puede verificar funcionamiento con foto estática. Se requiere prueba en vivo."
|
||||
- Si la imagen es borrosa o no permite análisis → Indica que tomen otra foto más clara
|
||||
- Si la imagen muestra un componente diferente al solicitado → Indica qué foto necesitan tomar
|
||||
|
||||
Responde SOLO en formato JSON válido (sin markdown, sin ```json):
|
||||
{{
|
||||
"status": "minor",
|
||||
"observations": "Describe lo que SÍ puedes ver en la imagen y explica por qué no puedes responder completamente la pregunta si aplica",
|
||||
"recommendation": "Si no puedes verificar lo solicitado con la imagen, explica claramente QUÉ se necesita (prueba en vivo, video, foto diferente, etc.)",
|
||||
"status": "ok",
|
||||
"observations": "Describe lo que observas en la imagen en relación a la tarea solicitada",
|
||||
"recommendation": "Acción sugerida basada en lo observado",
|
||||
"confidence": 0.85
|
||||
}}
|
||||
|
||||
VALORES DE STATUS:
|
||||
- "ok": Solo si puedes CONFIRMAR que todo está bien según las instrucciones
|
||||
- "minor": Si hay limitaciones en la imagen o no puedes verificar completamente lo solicitado
|
||||
- "critical": Si hay problemas graves visibles o la imagen es completamente inadecuada
|
||||
- "ok": Cumple con lo esperado según la tarea
|
||||
- "minor": Presenta observaciones menores o advertencias
|
||||
- "critical": Presenta problemas graves o no cumple con lo esperado
|
||||
|
||||
RECORDATORIO: En tus observaciones, menciona si el estado es apropiado para el kilometraje y marca/modelo del vehículo cuando sea relevante."""
|
||||
IMPORTANTE: Si la tarea requiere verificar funcionamiento (algo encendido, prendido, activo) pero la imagen muestra el componente apagado o en reposo, usa status "critical" e indica en "recommendation" que se necesita una foto con el componente funcionando o un video."""
|
||||
|
||||
if vehicle_context:
|
||||
user_message = f"Inspecciona esta imagen del vehículo. Las instrucciones específicas requieren: '{custom_prompt}'. Verifica si con esta imagen puedes responder completamente esa solicitud."
|
||||
else:
|
||||
user_message = f"Inspecciona la imagen. Las instrucciones requieren: '{custom_prompt}'. Verifica si puedes responder esa solicitud con esta imagen."
|
||||
user_message = f"Pregunta de inspección: {question_obj.text}\n\nAnaliza esta imagen según la tarea especificada."
|
||||
else:
|
||||
# Prompt altamente específico para la pregunta
|
||||
question_text = question_obj.text
|
||||
@@ -1682,6 +1695,13 @@ Responde SOLO en formato JSON válido (sin markdown, sin ```json):
|
||||
NOTA: "status" debe ser "ok" (bueno), "minor" (problemas leves) o "critical" (problemas graves)."""
|
||||
user_message = "Analiza este componente del vehículo para la inspección general."
|
||||
|
||||
print(f"\n🤖 PROMPT ENVIADO AL AI:")
|
||||
print(f"Provider: {ai_config.provider}")
|
||||
print(f"Model: {ai_config.model_name}")
|
||||
print(f"System prompt (primeros 200 chars): {system_prompt[:200]}...")
|
||||
print(f"User message: {user_message}")
|
||||
print("="*80 + "\n")
|
||||
|
||||
if ai_config.provider == "openai":
|
||||
import openai
|
||||
openai.api_key = ai_config.api_key
|
||||
|
||||
@@ -12,6 +12,7 @@ class User(Base):
|
||||
password_hash = Column(String(255), nullable=False)
|
||||
role = Column(String(20), nullable=False) # admin, mechanic, asesor
|
||||
full_name = Column(String(100))
|
||||
employee_code = Column(String(50)) # Nro Operario - código de otro sistema
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class UserBase(BaseModel):
|
||||
username: str
|
||||
email: Optional[EmailStr] = None
|
||||
full_name: Optional[str] = None
|
||||
employee_code: Optional[str] = None # Nro Operario - código de otro sistema
|
||||
role: str = "mechanic"
|
||||
|
||||
class UserCreate(UserBase):
|
||||
@@ -16,6 +17,7 @@ class UserUpdate(BaseModel):
|
||||
username: Optional[str] = None
|
||||
email: Optional[EmailStr] = None
|
||||
full_name: Optional[str] = None
|
||||
employee_code: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
|
||||
class UserPasswordUpdate(BaseModel):
|
||||
@@ -31,6 +33,7 @@ class UserLogin(BaseModel):
|
||||
|
||||
class User(UserBase):
|
||||
id: int
|
||||
employee_code: Optional[str] = None
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
|
||||
Reference in New Issue
Block a user