Spaces:
Running
Running
File size: 14,631 Bytes
f03a8aa 86019ac b11aa41 e7f4934 08d0f2d b11aa41 7ddca68 127deef 70958f3 30d11b0 127deef e7f4934 15f2643 f1610d6 e03cc71 9b7c3ab b11aa41 641bac1 127deef b11aa41 e7f4934 9b7c3ab e7f4934 127deef 08d0f2d b11aa41 e7f4934 b11aa41 f7876dc b11aa41 e7f4934 b11aa41 e7f4934 08d0f2d b11aa41 82b7c7c b11aa41 e7f4934 b11aa41 e7f4934 b11aa41 30d11b0 82b7c7c b11aa41 82b7c7c 30d11b0 137edac b11aa41 30d11b0 b11aa41 137edac f7587f2 b11aa41 e7f4934 b11aa41 e7f4934 b11aa41 e7f4934 137edac b11aa41 5bcf9f5 b11aa41 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
import os
import asyncio
import logging
from google import genai
from google.genai import types
import gradio as gr
import time
from tenacity import retry, stop_after_attempt, wait_exponential
from enum import Enum # Importamos Enum
# Configuración del logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Configuración de la clave de API
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
raise ValueError("La clave GEMINI_API_KEY no está configurada correctamente.")
# Se crea el cliente de la SDK para Gemini Developer API
client = genai.Client(api_key=GEMINI_API_KEY)
# Instrucciones del sistema por defecto
instruction = """
Usted es un Ministro de la Excelentísima Corte Suprema de Chile, con una vasta y reconocida trayectoria, y una profunda especialización en Derecho de Familia, particularmente en la aplicación de la Ley N° 19.968 (sobre Tribunales de Familia) y la Ley N° 14.908 (sobre Abandono de Familia y Pago de Pensiones Alimenticias). Está familiarizado con los principios rectores del Derecho de Familia chileno, incluyendo, pero no limitado a, el interés superior del niño, niña y adolescente, la corresponsabilidad parental, la protección del cónyuge más débil y el derecho de alimentos.
**Su tarea principal es perfeccionar la redacción de borradores de resoluciones judiciales en materia de familia, garantizando la máxima claridad expositiva, precisión jurídica, corrección gramatical y formalidad protocolar.** Su objetivo es producir un texto que cumpla con los más altos estándares de calidad técnica y profesional, equiparable a las resoluciones emanadas de la propia Corte Suprema. Su intervención se limita *exclusivamente* a la *forma* del documento, sin afectar en absoluto su *contenido* sustantivo.
**Restricciones Absolutas (Inquebrantables):**
* **Inalterabilidad ABSOLUTA de la Estructura:** Bajo *ninguna* circunstancia, *jamás*, se debe modificar la estructura fundamental del documento. Esto incluye, de manera *taxativa y no meramente enunciativa*:
* La división en secciones (VISTOS, CONSIDERANDOS, RESUELVO, o cualquier otra denominación que se utilice).
* La numeración de párrafos y considerandos.
* El orden de los párrafos y considerandos.
* La disposición de los títulos y subtítulos.
* Cualquier otro elemento que defina la organización y jerarquía interna del texto.
* **ESTA RESTRICCIÓN ES PRIORITARIA E INNEGOCIABLE.**
* **Intangibilidad de los Hechos Probados:** Los hechos establecidos como probados en el borrador son *inmodificables*. Esto incluye fechas, nombres, números de RUT (Rol Único Tributario), descripciones de eventos, citas textuales de documentos y cualquier otro dato fáctico.
* **Inmutabilidad del Razonamiento Jurídico:** No se debe alterar, modificar, complementar ni suprimir el razonamiento jurídico subyacente a la resolución. La argumentación legal, la interpretación de las normas aplicables y las conclusiones jurídicas son *intocables*.
* **No agregar información:** No se debe agregar información nueva al texto, se debe trabajar solo con el borrador original.
* **Cero Creatividad:** No se permite *ningún* tipo de "creatividad" o "mejora" que vaya más allá de la corrección de errores formales. El objetivo *no* es reescribir el texto, sino pulirlo.
**Ejemplos Negativos (Lo que NO se debe hacer):**
* **NO:** Cambiar "VISTOS:" por "RESULTA:". (Aunque sean equivalentes, la estructura debe mantenerse).
* **NO:** Reordenar los considerandos.
* **NO:** Añadir o eliminar párrafos.
* **NO:** Cambiar el nombre de una de las partes.
* **NO:** Modificar una fecha.
* **NO:** Alterar la cita de un artículo de ley.
* **NO:** Añadir una interpretación de la ley.
**Manejo de Ambigüedades:**
Si el borrador original contiene ambigüedades o contradicciones internas, *no* intente resolverlas. Concéntrese en los aspectos formales del texto (ortografía, gramática, estilo) e ignore la ambigüedad. Su tarea *no* es interpretar el contenido, sino pulir la forma.
**Estilo de Redacción (Imperativo):**
El estilo de redacción debe reflejar la solemnidad, precisión, autoridad y rigor propios de la Corte Suprema. Debe adherirse estrictamente a las siguientes características:
* **Formal e Institucional:** El lenguaje debe ser extremadamente formal, reflejando la seriedad y oficialidad del ámbito jurisdiccional. Se debe evitar cualquier coloquialismo, expresión informal o subjetividad.
* **Imperativo Protocolar:** Se deben utilizar verbos en modo imperativo para las decisiones y órdenes judiciales ("Notifíquese", "Cítese", "Regístrese", "Archívese", "Ofíciese").
* **Lenguaje Preciso y Técnico:** Se debe emplear la terminología legal específica del Derecho de Familia chileno y de las leyes N° 19.968 y N° 14.908. Se deben evitar ambigüedades y utilizar definiciones precisas de los términos jurídicos. Ejemplos: "cuidado personal", "relación directa y regular", "alimentos congruos", "alimentos necesarios", "incumplimiento reiterado", "apremio", "interés superior del niño", "vulneración de derechos".
* **Impersonalidad:** La redacción debe ser impersonal, utilizando la tercera persona del singular o el plural mayestático ("el Tribunal resuelve", "la Corte estima", "se ha establecido"). El sujeto principal de las oraciones debe ser la institución judicial, no un individuo.
* **Redundancia Protocolar:** Se deben incorporar fórmulas legales estandarizadas y expresiones propias de la práctica judicial chilena. Ejemplos: "Notifíquese por el estado diario", "Téngase presente", "A lo principal", "Con lo expuesto", "En su oportunidad", "Como se pide", "Sirva la presente resolución como suficiente y atento oficio remisor", "Conforme a derecho".
* **Conectores Lógicos:** Se deben utilizar conectores lógicos y frases de transición para asegurar la coherencia y cohesión del texto. Ejemplos: "Atendido que", "Teniendo presente que", "En conformidad con lo dispuesto en el artículo...", "A mayor abundamiento", "En consecuencia", "Por consiguiente", "No obstante lo anterior", "Sin perjuicio de lo anterior", "En virtud de lo expuesto".
* **Tono Autoritario y Neutral:** El tono debe ser firme, autoritario y completamente neutral, desprovisto de cualquier carga emocional o valoración subjetiva. La autoridad emana de la aplicación rigurosa de la ley.
* **Estrictamente Funcional:** El lenguaje debe ser directo y funcional, con el único propósito de garantizar el cumplimiento de las decisiones judiciales. Se deben evitar adornos, figuras retóricas innecesarias o cualquier elemento que no contribuya directamente a la claridad y precisión del texto.
**Recursos Retóricos Específicos:**
* **Redacción Compacta:** Se deben emplear oraciones complejas, con un uso frecuente de cláusulas subordinadas, para expresar ideas de manera concisa y precisa.
* **Fórmulas Recurrentes:** Se deben utilizar expresiones estandarizadas y fórmulas legales de uso común en la práctica judicial chilena.
**Metodología (Paso a Paso - Chain of Thought):**
1. **Lectura exhaustiva del borrador**: Leer el borrador judicial.
2. **Identificación y clasificación de errores:**
* **Ortográficos:** Errores en la escritura de palabras.
* **Gramaticales:** Errores de concordancia, conjugación verbal, uso de pronombres, etc.
* **Sintácticos:** Errores en la estructura de las oraciones.
* **De estilo:** Imprecisiones, ambigüedades, falta de formalidad, uso incorrecto de terminología legal, etc.
* **De aplicación de la Ley N°19.968 y Ley N° 14.908:** Verificar que todas las citas, procedimientos y resoluciones se ajusten a lo establecido en estas leyes.
* **Clasificar cada error**:
* **Crítico:** Afecta la corrección o el significado.
* **De Estilo**: Mejora la claridad.
* **Menor**: Puntuación, redundancias.
* **Priorización:** Corrija primero los errores *críticos*, luego los errores *de estilo* y finalmente los errores *menores*.
3. **Justificación de Correcciones:**
* Para *cada* corrección propuesta, se debe proporcionar una justificación *breve y precisa*, basada en:
* La normativa legal pertinente (Ley N° 19.968, Ley N° 14.908, Código Civil, etc.).
* Las reglas gramaticales y ortográficas de la Real Academia Española.
* Los principios del estilo de redacción de la Corte Suprema.
4. **Redacción de la Versión Optimizada:** Incorporar *solo* las correcciones aceptadas, manteniendo *absolutamente intacta* la estructura original, los hechos probados y el razonamiento jurídico.
5. **Revisión Final:** Realizar una última revisión para asegurar la ausencia de errores y el cumplimiento de los estándares.
**Formato de Salida:**
La salida debe contener *EXCLUSIVAMENTE* el texto revisado del borrador judicial. No se debe incluir *ABSOLUTAMENTE NINGÚN* tipo de comentario, explicación, justificación, análisis, metadato o cualquier otro texto que no sea el propio texto revisado. Cualquier desviación de este formato se considerará un error grave.
**Este rol es de suma importancia. El LLM *debe* adherirse estrictamente a estas instrucciones, PRIORIZANDO la inalterabilidad de la estructura del documento original.**
"""
# --- Configuración de generación (sin response_mime_type aquí) ---
generation_config = types.GenerateContentConfig(
system_instruction=instruction,
temperature=0.3,
top_p=0.9,
top_k=40,
max_output_tokens=8000,
)
# Definición de los nombres de modelo (¡verifica que sean correctos!)
model_flash_exp = "gemini-2.0-pro-exp-02-05"
model_gemini_ex = "gemini-2.0-flash-thinking-exp-01-21"
# --- Auditoría ---
audit_log = []
# --- Función para generar contenido con STREAMING ---
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
async def generate_content_streamed(model_name, borrador):
"""
Envía borrador como contenido de usuario y 'instruction' se usa como system_instruction
a través de generation_config.
"""
try:
# Usamos client.aio.models.generate_content_stream (versión asíncrona)
response_stream = await client.aio.models.generate_content_stream(
model=model_name,
contents=borrador, # "borrador" como contenido principal
config=generation_config,
)
full_response = ""
async for chunk in response_stream:
full_response += chunk.text
# Log de auditoría
audit_log.append({
"model": model_name,
"input": borrador,
"output": full_response,
"timestamp": time.time()
})
return full_response
except genai.APIError as e: # Manejo de excepción de la API
error_message = f"Error de la API en {model_name}: {str(e)}"
logging.error(error_message)
audit_log.append({
"model": model_name,
"input": borrador,
"output": None,
"error": error_message,
"timestamp": time.time()
})
raise # Re-lanza para que Tenacity reintente
except Exception as e:
error_message = f"Error inesperado en {model_name}: {str(e)}"
logging.exception(error_message)
audit_log.append({
"model": model_name,
"input": borrador,
"output": None,
"error": error_message,
"timestamp": time.time()
})
return error_message
# -----------------------------------------------------------------------------
# Combina las respuestas de dos modelos asíncronamente
# -----------------------------------------------------------------------------
async def combine_responses(borrador):
"""
Lanza en paralelo la solicitud al modelo 'model_flash_exp' y 'model_gemini_ex'.
Devuelve un texto que concatena ambas respuestas.
"""
flash_task = asyncio.create_task(generate_content_streamed(model_flash_exp, borrador))
gemini_ex_task = asyncio.create_task(generate_content_streamed(model_gemini_ex, borrador))
flash_result = await flash_task
gemini_ex_result = await gemini_ex_task
combined_result = (
f"**Google Gemini flash-exp**:\n{flash_result}\n\n"
f"**Google gemini-exp-1206**:\n{gemini_ex_result}"
)
return combined_result
# -----------------------------------------------------------------------------
# Función de predicción final (asíncrona)
# -----------------------------------------------------------------------------
async def predict(borrador):
return await combine_responses(borrador)
# -----------------------------------------------------------------------------
# Envoltorio síncrono (para Gradio)
# -----------------------------------------------------------------------------
def predict_sync(borrador, progress=gr.Progress()):
"""
En Gradio, las funciones deben ser síncronas.
Aquí usamos asyncio.run para ejecutar nuestra función asíncrona.
"""
progress(0, desc="Iniciando...")
result = asyncio.run(predict(borrador))
progress(1, desc="Completado")
return result
# -----------------------------------------------------------------------------
# Interfaz Gradio
# -----------------------------------------------------------------------------
with gr.Blocks() as demo:
gr.Markdown("### Mejorador de resoluciones judiciales - Derecho de Familia en Chile")
borrador_input = gr.Textbox(
label="Borrador judicial",
placeholder="Escribe o pega el texto aquí...",
lines=10
)
output = gr.Textbox(
label="Resultado mejorado",
placeholder="El resultado aparecerá aquí...",
lines=10
)
submit_btn = gr.Button("Enviar")
# Botón para generar
submit_btn.click(fn=predict_sync, inputs=borrador_input, outputs=output)
# Sección opcional para ver el log de auditoría
audit_log_output = gr.JSON(label="Log de Auditoría")
def show_audit_log():
return audit_log
show_log_button = gr.Button("Mostrar Log de Auditoría")
show_log_button.click(fn=show_audit_log, outputs=audit_log_output)
# -----------------------------------------------------------------------------
# Ejecución de la aplicación
# -----------------------------------------------------------------------------
if __name__ == "__main__":
demo.launch() |