feat: AI prompts personalizados por pregunta - backend v1.0.13, frontend v1.0.21

Backend:
- Agregar campo ai_prompt a tabla questions
- Endpoint analyze-image recibe custom_prompt
- Validación de imagen apropiada (sugiere cambiar foto si no corresponde)
- Script de migración migrate_ai_prompt.py

Frontend:
- Campo de texto para configurar prompt de IA en editor de preguntas
- Envía custom_prompt al endpoint de análisis
- UI con fondo morado para sección de IA

La IA ahora analiza fotos según el contexto específico de cada pregunta
y sugiere cambiar la imagen si no corresponde al componente solicitado.
This commit is contained in:
2025-11-21 02:41:50 -03:00
parent 678a8cd24b
commit 2b5424790a
6 changed files with 110 additions and 12 deletions

View File

@@ -1029,6 +1029,7 @@ def delete_ai_configuration(
async def analyze_image(
file: UploadFile = File(...),
question_id: int = None,
custom_prompt: str = None,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user)
):
@@ -1061,12 +1062,37 @@ async def analyze_image(
try:
# Construir prompt dinámico basado en la pregunta específica
if question_obj:
# Prompt altamente específico para la pregunta
question_text = question_obj.text
question_type = question_obj.type
section = question_obj.section
system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular.
# Usar prompt personalizado si está disponible
if custom_prompt:
# Prompt 100% personalizado por el administrador
system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular.
INSTRUCCIONES ESPECÍFICAS PARA ESTA PREGUNTA:
{custom_prompt}
PREGUNTA A RESPONDER: "{question_obj.text}"
Sección: {question_obj.section}
Analiza la imagen siguiendo EXACTAMENTE las instrucciones proporcionadas arriba.
VALIDACIÓN DE IMAGEN:
- Si la imagen NO corresponde al contexto de la pregunta (por ejemplo, si piden luces pero muestran motor), indica en "recommendation" que deben cambiar la foto
- Si la imagen es borrosa, oscura o no permite análisis, indica en "recommendation" que tomen otra foto más clara
Responde en formato JSON:
{{
"status": "ok|minor|critical",
"observations": "Análisis específico según el prompt personalizado",
"recommendation": "Si la imagen no es apropiada, indica 'Por favor tome una foto de [componente correcto]'. Si es apropiada, da recomendación técnica.",
"confidence": 0.0-1.0
}}"""
else:
# Prompt altamente específico para la pregunta
question_text = question_obj.text
question_type = question_obj.type
section = question_obj.section
system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular.
PREGUNTA ESPECÍFICA A RESPONDER: "{question_text}"
Sección: {section}
@@ -1074,11 +1100,15 @@ Sección: {section}
Analiza la imagen ÚNICAMENTE para responder esta pregunta específica.
Sé directo y enfócate solo en lo que la pregunta solicita.
VALIDACIÓN DE IMAGEN:
- Si la imagen NO corresponde al contexto de la pregunta, indica en "recommendation" que deben cambiar la foto
- Si la imagen es borrosa o no permite análisis, indica en "recommendation" que tomen otra foto más clara
Responde en formato JSON:
{{
"status": "ok|minor|critical",
"observations": "Respuesta específica a: {question_text}",
"recommendation": "Acción si aplica",
"recommendation": "Si la imagen no es apropiada, indica 'Por favor tome una foto de [componente correcto]'. Si es apropiada, da acción técnica si aplica.",
"confidence": 0.0-1.0
}}
@@ -1089,7 +1119,7 @@ IMPORTANTE:
- Si la pregunta es pass/fail, indica claramente si pasa o falla
- Si la pregunta es bueno/regular/malo, indica el estado específico del componente"""
user_message = f"Inspecciona la imagen y responde específicamente: {question_text}"
user_message = f"Inspecciona la imagen y responde específicamente: {question_obj.text}"
else:
# Fallback para análisis general
system_prompt = """Eres un experto mecánico automotriz. Analiza la imagen y proporciona:

View File

@@ -76,6 +76,9 @@ class Question(Base):
parent_question_id = Column(Integer, ForeignKey("questions.id"), nullable=True)
show_if_answer = Column(String(50), nullable=True) # Valor que dispara esta pregunta
# AI Analysis
ai_prompt = Column(Text, nullable=True) # Prompt personalizado para análisis de IA de esta pregunta
created_at = Column(DateTime(timezone=True), server_default=func.now())
# Relationships

View File

@@ -99,6 +99,7 @@ class QuestionBase(BaseModel):
requires_comment_on_fail: bool = False
parent_question_id: Optional[int] = None
show_if_answer: Optional[str] = None
ai_prompt: Optional[str] = None
class QuestionCreate(QuestionBase):
checklist_id: int

View File

@@ -0,0 +1,32 @@
"""
Migration: Add ai_prompt column to questions table
Date: 2025-11-21
Description: Adds ai_prompt TEXT column for custom AI analysis prompts per question
"""
# SQL Migration Script
sql_statements = [
# Add ai_prompt column
"""
ALTER TABLE questions
ADD COLUMN ai_prompt TEXT;
""",
]
# To apply this migration, run these SQL statements in your PostgreSQL database:
if __name__ == "__main__":
print("=" * 80)
print("MIGRATION: Add ai_prompt to questions table")
print("=" * 80)
print("\nExecute the following SQL statements in your PostgreSQL database:\n")
for i, statement in enumerate(sql_statements, 1):
print(f"-- Statement {i}")
print(statement.strip())
print()
print("=" * 80)
print("\nTo verify the migration:")
print("SELECT column_name, data_type FROM information_schema.columns")
print("WHERE table_name = 'questions' AND column_name = 'ai_prompt';")
print("=" * 80)